rubyvis 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,86 +0,0 @@
1
- /**
2
- * Abstract; see the various scale implementations.
3
- *
4
- * @class Represents a scale; a function that performs a transformation from
5
- * data domain to visual range. For quantitative and quantile scales, the domain
6
- * is expressed as numbers; for ordinal scales, the domain is expressed as
7
- * strings (or equivalently objects with unique string representations). The
8
- * "visual range" may correspond to pixel space, colors, font sizes, and the
9
- * like.
10
- *
11
- * <p>Note that scales are functions, and thus can be used as properties
12
- * directly, assuming that the data associated with a mark is a number. While
13
- * this is convenient for single-use scales, frequently it is desirable to
14
- * define scales globally:
15
- *
16
- * <pre>var y = pv.Scale.linear(0, 100).range(0, 640);</pre>
17
- *
18
- * The <tt>y</tt> scale can now be equivalently referenced within a property:
19
- *
20
- * <pre> .height(function(d) y(d))</pre>
21
- *
22
- * Alternatively, if the data are not simple numbers, the appropriate value can
23
- * be passed to the <tt>y</tt> scale (e.g., <tt>d.foo</tt>). The {@link #by}
24
- * method similarly allows the data to be mapped to a numeric value before
25
- * performing the linear transformation.
26
- *
27
- * @see pv.Scale.quantitative
28
- * @see pv.Scale.quantile
29
- * @see pv.Scale.ordinal
30
- * @extends function
31
- */
32
- pv.Scale = function() {};
33
-
34
- /**
35
- * @private Returns a function that interpolators from the start value to the
36
- * end value, given a parameter <i>t</i> in [0, 1].
37
- *
38
- * @param start the start value.
39
- * @param end the end value.
40
- */
41
- pv.Scale.interpolator = function(start, end) {
42
- if (typeof start == "number") {
43
- return function(t) {
44
- return t * (end - start) + start;
45
- };
46
- }
47
-
48
- /* For now, assume color. */
49
- start = pv.color(start).rgb();
50
- end = pv.color(end).rgb();
51
- return function(t) {
52
- var a = start.a * (1 - t) + end.a * t;
53
- if (a < 1e-5) a = 0; // avoid scientific notation
54
- return (start.a == 0) ? pv.rgb(end.r, end.g, end.b, a)
55
- : ((end.a == 0) ? pv.rgb(start.r, start.g, start.b, a)
56
- : pv.rgb(
57
- Math.round(start.r * (1 - t) + end.r * t),
58
- Math.round(start.g * (1 - t) + end.g * t),
59
- Math.round(start.b * (1 - t) + end.b * t), a));
60
- };
61
- };
62
-
63
- /**
64
- * Returns a view of this scale by the specified accessor function <tt>f</tt>.
65
- * Given a scale <tt>y</tt>, <tt>y.by(function(d) d.foo)</tt> is equivalent to
66
- * <tt>function(d) y(d.foo)</tt>.
67
- *
68
- * <p>This method is provided for convenience, such that scales can be
69
- * succinctly defined inline. For example, given an array of data elements that
70
- * have a <tt>score</tt> attribute with the domain [0, 1], the height property
71
- * could be specified as:
72
- *
73
- * <pre> .height(pv.Scale.linear().range(0, 480).by(function(d) d.score))</pre>
74
- *
75
- * This is equivalent to:
76
- *
77
- * <pre> .height(function(d) d.score * 480)</pre>
78
- *
79
- * This method should be used judiciously; it is typically more clear to invoke
80
- * the scale directly, passing in the value to be scaled.
81
- *
82
- * @function
83
- * @name pv.Scale.prototype.by
84
- * @param {function} f an accessor function.
85
- * @returns {pv.Scale} a view of this scale by the specified accessor function.
86
- */
@@ -1,109 +0,0 @@
1
- /**
2
- * Returns a new identity transform.
3
- *
4
- * @class Represents a transformation matrix. The transformation matrix is
5
- * limited to expressing translate and uniform scale transforms only; shearing,
6
- * rotation, general affine, and other transforms are not supported.
7
- *
8
- * <p>The methods on this class treat the transform as immutable, returning a
9
- * copy of the transformation matrix with the specified transform applied. Note,
10
- * alternatively, that the matrix fields can be get and set directly.
11
- */
12
- pv.Transform = function() {};
13
- pv.Transform.prototype = {k: 1, x: 0, y: 0};
14
-
15
- /**
16
- * The scale magnitude; defaults to 1.
17
- *
18
- * @type number
19
- * @name pv.Transform.prototype.k
20
- */
21
-
22
- /**
23
- * The x-offset; defaults to 0.
24
- *
25
- * @type number
26
- * @name pv.Transform.prototype.x
27
- */
28
-
29
- /**
30
- * The y-offset; defaults to 0.
31
- *
32
- * @type number
33
- * @name pv.Transform.prototype.y
34
- */
35
-
36
- /**
37
- * @private The identity transform.
38
- *
39
- * @type pv.Transform
40
- */
41
- pv.Transform.identity = new pv.Transform();
42
-
43
- // k 0 x 1 0 a k 0 ka+x
44
- // 0 k y * 0 1 b = 0 k kb+y
45
- // 0 0 1 0 0 1 0 0 1
46
-
47
- /**
48
- * Returns a translated copy of this transformation matrix.
49
- *
50
- * @param {number} x the x-offset.
51
- * @param {number} y the y-offset.
52
- * @returns {pv.Transform} the translated transformation matrix.
53
- */
54
- pv.Transform.prototype.translate = function(x, y) {
55
- var v = new pv.Transform();
56
- v.k = this.k;
57
- v.x = this.k * x + this.x;
58
- v.y = this.k * y + this.y;
59
- return v;
60
- };
61
-
62
- // k 0 x d 0 0 kd 0 x
63
- // 0 k y * 0 d 0 = 0 kd y
64
- // 0 0 1 0 0 1 0 0 1
65
-
66
- /**
67
- * Returns a scaled copy of this transformation matrix.
68
- *
69
- * @param {number} k
70
- * @returns {pv.Transform} the scaled transformation matrix.
71
- */
72
- pv.Transform.prototype.scale = function(k) {
73
- var v = new pv.Transform();
74
- v.k = this.k * k;
75
- v.x = this.x;
76
- v.y = this.y;
77
- return v;
78
- };
79
-
80
- /**
81
- * Returns the inverse of this transformation matrix.
82
- *
83
- * @returns {pv.Transform} the inverted transformation matrix.
84
- */
85
- pv.Transform.prototype.invert = function() {
86
- var v = new pv.Transform(), k = 1 / this.k;
87
- v.k = k;
88
- v.x = -this.x * k;
89
- v.y = -this.y * k;
90
- return v;
91
- };
92
-
93
- // k 0 x d 0 a kd 0 ka+x
94
- // 0 k y * 0 d b = 0 kd kb+y
95
- // 0 0 1 0 0 1 0 0 1
96
-
97
- /**
98
- * Returns this matrix post-multiplied by the specified matrix <i>m</i>.
99
- *
100
- * @param {pv.Transform} m
101
- * @returns {pv.Transform} the post-multiplied transformation matrix.
102
- */
103
- pv.Transform.prototype.times = function(m) {
104
- var v = new pv.Transform();
105
- v.k = this.k * m.k;
106
- v.x = this.k * m.x + this.x;
107
- v.y = this.k * m.y + this.y;
108
- return v;
109
- };
@@ -1,124 +0,0 @@
1
- /**
2
- * Returns a {@link pv.Tree} operator for the specified array. This is a
3
- * convenience factory method, equivalent to <tt>new pv.Tree(array)</tt>.
4
- *
5
- * @see pv.Tree
6
- * @param {array} array an array from which to construct a tree.
7
- * @returns {pv.Tree} a tree operator for the specified array.
8
- */
9
- pv.tree = function(array) {
10
- return new pv.Tree(array);
11
- };
12
-
13
- /**
14
- * Constructs a tree operator for the specified array. This constructor should
15
- * not be invoked directly; use {@link pv.tree} instead.
16
- *
17
- * @class Represents a tree operator for the specified array. The tree operator
18
- * allows a hierarchical map to be constructed from an array; it is similar to
19
- * the {@link pv.Nest} operator, except the hierarchy is derived dynamically
20
- * from the array elements.
21
- *
22
- * <p>For example, given an array of size information for ActionScript classes:
23
- *
24
- * <pre>{ name: "flare.flex.FlareVis", size: 4116 },
25
- * { name: "flare.physics.DragForce", size: 1082 },
26
- * { name: "flare.physics.GravityForce", size: 1336 }, ...</pre>
27
- *
28
- * To facilitate visualization, it may be useful to nest the elements by their
29
- * package hierarchy:
30
- *
31
- * <pre>var tree = pv.tree(classes)
32
- * .keys(function(d) d.name.split("."))
33
- * .map();</pre>
34
- *
35
- * The resulting tree is:
36
- *
37
- * <pre>{ flare: {
38
- * flex: {
39
- * FlareVis: {
40
- * name: "flare.flex.FlareVis",
41
- * size: 4116 } },
42
- * physics: {
43
- * DragForce: {
44
- * name: "flare.physics.DragForce",
45
- * size: 1082 },
46
- * GravityForce: {
47
- * name: "flare.physics.GravityForce",
48
- * size: 1336 } },
49
- * ... } }</pre>
50
- *
51
- * By specifying a value function,
52
- *
53
- * <pre>var tree = pv.tree(classes)
54
- * .keys(function(d) d.name.split("."))
55
- * .value(function(d) d.size)
56
- * .map();</pre>
57
- *
58
- * we can further eliminate redundant data:
59
- *
60
- * <pre>{ flare: {
61
- * flex: {
62
- * FlareVis: 4116 },
63
- * physics: {
64
- * DragForce: 1082,
65
- * GravityForce: 1336 },
66
- * ... } }</pre>
67
- *
68
- * For visualizations with large data sets, performance improvements may be seen
69
- * by storing the data in a tree format, and then flattening it into an array at
70
- * runtime with {@link pv.Flatten}.
71
- *
72
- * @param {array} array an array from which to construct a tree.
73
- */
74
- pv.Tree = function(array) {
75
- this.array = array;
76
- };
77
-
78
- /**
79
- * Assigns a <i>keys</i> function to this operator; required. The keys function
80
- * returns an array of <tt>string</tt>s for each element in the associated
81
- * array; these keys determine how the elements are nested in the tree. The
82
- * returned keys should be unique for each element in the array; otherwise, the
83
- * behavior of this operator is undefined.
84
- *
85
- * @param {function} k the keys function.
86
- * @returns {pv.Tree} this.
87
- */
88
- pv.Tree.prototype.keys = function(k) {
89
- this.k = k;
90
- return this;
91
- };
92
-
93
- /**
94
- * Assigns a <i>value</i> function to this operator; optional. The value
95
- * function specifies an optional transformation of the element in the array
96
- * before it is inserted into the map. If no value function is specified, it is
97
- * equivalent to using the identity function.
98
- *
99
- * @param {function} k the value function.
100
- * @returns {pv.Tree} this.
101
- */
102
- pv.Tree.prototype.value = function(v) {
103
- this.v = v;
104
- return this;
105
- };
106
-
107
- /**
108
- * Returns a hierarchical map of values. The hierarchy is determined by the keys
109
- * function; the values in the map are determined by the value function.
110
- *
111
- * @returns a hierarchical map of values.
112
- */
113
- pv.Tree.prototype.map = function() {
114
- var map = {}, o = {};
115
- for (var i = 0; i < this.array.length; i++) {
116
- o.index = i;
117
- var value = this.array[i], keys = this.k.call(o, value), node = map;
118
- for (var j = 0; j < keys.length - 1; j++) {
119
- node = node[keys[j]] || (node[keys[j]] = {});
120
- }
121
- node[keys[j]] = this.v ? this.v.call(o, value) : value;
122
- }
123
- return map;
124
- };
@@ -1,118 +0,0 @@
1
- /**
2
- * Returns a {@link pv.Vector} for the specified <i>x</i> and <i>y</i>
3
- * coordinate. This is a convenience factory method, equivalent to <tt>new
4
- * pv.Vector(x, y)</tt>.
5
- *
6
- * @see pv.Vector
7
- * @param {number} x the <i>x</i> coordinate.
8
- * @param {number} y the <i>y</i> coordinate.
9
- * @returns {pv.Vector} a vector for the specified coordinates.
10
- */
11
- pv.vector = function(x, y) {
12
- return new pv.Vector(x, y);
13
- };
14
-
15
- /**
16
- * Constructs a {@link pv.Vector} for the specified <i>x</i> and <i>y</i>
17
- * coordinate. This constructor should not be invoked directly; use
18
- * {@link pv.vector} instead.
19
- *
20
- * @class Represents a two-dimensional vector; a 2-tuple <i>&#x27e8;x,
21
- * y&#x27e9;</i>. The intent of this class is to simplify vector math. Note that
22
- * in performance-sensitive cases it may be more efficient to represent 2D
23
- * vectors as simple objects with <tt>x</tt> and <tt>y</tt> attributes, rather
24
- * than using instances of this class.
25
- *
26
- * @param {number} x the <i>x</i> coordinate.
27
- * @param {number} y the <i>y</i> coordinate.
28
- */
29
- pv.Vector = function(x, y) {
30
- this.x = x;
31
- this.y = y;
32
- };
33
-
34
- /**
35
- * Returns a vector perpendicular to this vector: <i>&#x27e8;-y, x&#x27e9;</i>.
36
- *
37
- * @returns {pv.Vector} a perpendicular vector.
38
- */
39
- pv.Vector.prototype.perp = function() {
40
- return new pv.Vector(-this.y, this.x);
41
- };
42
-
43
- /**
44
- * Returns a normalized copy of this vector: a vector with the same direction,
45
- * but unit length. If this vector has zero length this method returns a copy of
46
- * this vector.
47
- *
48
- * @returns {pv.Vector} a unit vector.
49
- */
50
- pv.Vector.prototype.norm = function() {
51
- var l = this.length();
52
- return this.times(l ? (1 / l) : 1);
53
- };
54
-
55
- /**
56
- * Returns the magnitude of this vector, defined as <i>sqrt(x * x + y * y)</i>.
57
- *
58
- * @returns {number} a length.
59
- */
60
- pv.Vector.prototype.length = function() {
61
- return Math.sqrt(this.x * this.x + this.y * this.y);
62
- };
63
-
64
- /**
65
- * Returns a scaled copy of this vector: <i>&#x27e8;x * k, y * k&#x27e9;</i>.
66
- * To perform the equivalent divide operation, use <i>1 / k</i>.
67
- *
68
- * @param {number} k the scale factor.
69
- * @returns {pv.Vector} a scaled vector.
70
- */
71
- pv.Vector.prototype.times = function(k) {
72
- return new pv.Vector(this.x * k, this.y * k);
73
- };
74
-
75
- /**
76
- * Returns this vector plus the vector <i>v</i>: <i>&#x27e8;x + v.x, y +
77
- * v.y&#x27e9;</i>. If only one argument is specified, it is interpreted as the
78
- * vector <i>v</i>.
79
- *
80
- * @param {number} x the <i>x</i> coordinate to add.
81
- * @param {number} y the <i>y</i> coordinate to add.
82
- * @returns {pv.Vector} a new vector.
83
- */
84
- pv.Vector.prototype.plus = function(x, y) {
85
- return (arguments.length == 1)
86
- ? new pv.Vector(this.x + x.x, this.y + x.y)
87
- : new pv.Vector(this.x + x, this.y + y);
88
- };
89
-
90
- /**
91
- * Returns this vector minus the vector <i>v</i>: <i>&#x27e8;x - v.x, y -
92
- * v.y&#x27e9;</i>. If only one argument is specified, it is interpreted as the
93
- * vector <i>v</i>.
94
- *
95
- * @param {number} x the <i>x</i> coordinate to subtract.
96
- * @param {number} y the <i>y</i> coordinate to subtract.
97
- * @returns {pv.Vector} a new vector.
98
- */
99
- pv.Vector.prototype.minus = function(x, y) {
100
- return (arguments.length == 1)
101
- ? new pv.Vector(this.x - x.x, this.y - x.y)
102
- : new pv.Vector(this.x - x, this.y - y);
103
- };
104
-
105
- /**
106
- * Returns the dot product of this vector and the vector <i>v</i>: <i>x * v.x +
107
- * y * v.y</i>. If only one argument is specified, it is interpreted as the
108
- * vector <i>v</i>.
109
- *
110
- * @param {number} x the <i>x</i> coordinate to dot.
111
- * @param {number} y the <i>y</i> coordinate to dot.
112
- * @returns {number} a dot product.
113
- */
114
- pv.Vector.prototype.dot = function(x, y) {
115
- return (arguments.length == 1)
116
- ? this.x * x.x + this.y * x.y
117
- : this.x * x + this.y * y;
118
- };
@@ -1,5 +0,0 @@
1
- /**
2
- * @ignore
3
- * @namespace
4
- */
5
- pv.Geo = function() {};
@@ -1,307 +0,0 @@
1
- /**
2
- * Returns a geographic scale. The arguments to this constructor are optional,
3
- * and equivalent to calling {@link #projection}.
4
- *
5
- * @class Represents a geographic scale; a mapping between latitude-longitude
6
- * coordinates and screen pixel coordinates. By default, the domain is inferred
7
- * from the geographic coordinates, so that the domain fills the output range.
8
- *
9
- * <p>Note that geographic scales are two-dimensional transformations, rather
10
- * than the one-dimensional bidrectional mapping typical of other scales.
11
- * Rather than mapping (for example) between a numeric domain and a numeric
12
- * range, geographic scales map between two coordinate objects: {@link
13
- * pv.Geo.LatLng} and {@link pv.Vector}.
14
- *
15
- * @param {pv.Geo.Projection} [p] optional projection.
16
- * @see pv.Geo.scale#ticks
17
- */
18
- pv.Geo.scale = function(p) {
19
- var rmin = {x: 0, y: 0}, // default range minimum
20
- rmax = {x: 1, y: 1}, // default range maximum
21
- d = [], // default domain
22
- j = pv.Geo.projections.identity, // domain <-> normalized range
23
- x = pv.Scale.linear(-1, 1).range(0, 1), // normalized <-> range
24
- y = pv.Scale.linear(-1, 1).range(1, 0), // normalized <-> range
25
- c = {lng: 0, lat: 0}, // Center Point
26
- lastLatLng, // cached latlng
27
- lastPoint; // cached point
28
-
29
- /** @private */
30
- function scale(latlng) {
31
- if (!lastLatLng
32
- || (latlng.lng != lastLatLng.lng)
33
- || (latlng.lat != lastLatLng.lat)) {
34
- lastLatLng = latlng;
35
- var p = project(latlng);
36
- lastPoint = {x: x(p.x), y: y(p.y)};
37
- }
38
- return lastPoint;
39
- }
40
-
41
- /** @private */
42
- function project(latlng) {
43
- var offset = {lng: latlng.lng - c.lng, lat: latlng.lat};
44
- return j.project(offset);
45
- }
46
-
47
- /** @private */
48
- function invert(xy) {
49
- var latlng = j.invert(xy);
50
- latlng.lng += c.lng;
51
- return latlng;
52
- }
53
-
54
- /** Returns the projected x-coordinate. */
55
- scale.x = function(latlng) {
56
- return scale(latlng).x;
57
- };
58
-
59
- /** Returns the projected y-coordinate. */
60
- scale.y = function(latlng) {
61
- return scale(latlng).y;
62
- };
63
-
64
- /**
65
- * Abstract; this is a local namespace on a given geographic scale.
66
- *
67
- * @namespace Tick functions for geographic scales. Because geographic scales
68
- * represent two-dimensional transformations (as opposed to one-dimensional
69
- * transformations typical of other scales), the tick values are similarly
70
- * represented as two-dimensional coordinates in the input domain, i.e.,
71
- * {@link pv.Geo.LatLng} objects.
72
- *
73
- * <p>Also, note that non-rectilinear projections, such as sinsuoidal and
74
- * aitoff, may not produce straight lines for constant longitude or constant
75
- * latitude. Therefore the returned array of ticks is a two-dimensional array,
76
- * sampling various latitudes as constant longitude, and vice versa.
77
- *
78
- * <p>The tick lines can therefore be approximated as polylines, either with
79
- * "linear" or "cardinal" interpolation. This is not as accurate as drawing
80
- * the true curve through the projection space, but is usually sufficient.
81
- *
82
- * @name pv.Geo.scale.prototype.ticks
83
- * @see pv.Geo.scale
84
- * @see pv.Geo.LatLng
85
- * @see pv.Line#interpolate
86
- */
87
- scale.ticks = {
88
-
89
- /**
90
- * Returns longitude ticks.
91
- *
92
- * @function
93
- * @param {number} [m] the desired number of ticks.
94
- * @returns {array} a nested array of <tt>pv.Geo.LatLng</tt> ticks.
95
- * @name pv.Geo.scale.prototype.ticks.prototype.lng
96
- */
97
- lng: function(m) {
98
- var lat, lng;
99
- if (d.length > 1) {
100
- var s = pv.Scale.linear();
101
- if (m == undefined) m = 10;
102
- lat = s.domain(d, function(d) { return d.lat; }).ticks(m);
103
- lng = s.domain(d, function(d) { return d.lng; }).ticks(m);
104
- } else {
105
- lat = pv.range(-80, 81, 10);
106
- lng = pv.range(-180, 181, 10);
107
- }
108
- return lng.map(function(lng) {
109
- return lat.map(function(lat) {
110
- return {lat: lat, lng: lng};
111
- });
112
- });
113
- },
114
-
115
- /**
116
- * Returns latitude ticks.
117
- *
118
- * @function
119
- * @param {number} [m] the desired number of ticks.
120
- * @returns {array} a nested array of <tt>pv.Geo.LatLng</tt> ticks.
121
- * @name pv.Geo.scale.prototype.ticks.prototype.lat
122
- */
123
- lat: function(m) {
124
- return pv.transpose(scale.ticks.lng(m));
125
- }
126
- };
127
-
128
- /**
129
- * Inverts the specified value in the output range, returning the
130
- * corresponding value in the input domain. This is frequently used to convert
131
- * the mouse location (see {@link pv.Mark#mouse}) to a value in the input
132
- * domain. Inversion is only supported for numeric ranges, and not colors.
133
- *
134
- * <p>Note that this method does not do any rounding or bounds checking. If
135
- * the input domain is discrete (e.g., an array index), the returned value
136
- * should be rounded. If the specified <tt>y</tt> value is outside the range,
137
- * the returned value may be equivalently outside the input domain.
138
- *
139
- * @function
140
- * @name pv.Geo.scale.prototype.invert
141
- * @param {number} y a value in the output range (a pixel location).
142
- * @returns {number} a value in the input domain.
143
- */
144
- scale.invert = function(p) {
145
- return invert({x: x.invert(p.x), y: y.invert(p.y)});
146
- };
147
-
148
- /**
149
- * Sets or gets the input domain. Note that unlike quantitative scales, the
150
- * domain cannot be reduced to a simple rectangle (i.e., minimum and maximum
151
- * values for latitude and longitude). Instead, the domain values must be
152
- * projected to normalized space, effectively finding the domain in normalized
153
- * space rather than in terms of latitude and longitude. Thus, changing the
154
- * projection requires recomputing the normalized domain.
155
- *
156
- * <p>This method can be invoked several ways:
157
- *
158
- * <p>1. <tt>domain(values...)</tt>
159
- *
160
- * <p>Specifying the domain as a series of {@link pv.Geo.LatLng}s is the most
161
- * explicit and recommended approach. However, if the domain values are
162
- * derived from data, you may find the second method more appropriate.
163
- *
164
- * <p>2. <tt>domain(array, f)</tt>
165
- *
166
- * <p>Rather than enumerating the domain explicitly, you can specify a single
167
- * argument of an array. In addition, you can specify an optional accessor
168
- * function to extract the domain values (as {@link pv.Geo.LatLng}s) from the
169
- * array. If the specified array has fewer than two elements, this scale will
170
- * default to the full normalized domain.
171
- *
172
- * <p>2. <tt>domain()</tt>
173
- *
174
- * <p>Invoking the <tt>domain</tt> method with no arguments returns the
175
- * current domain as an array.
176
- *
177
- * @function
178
- * @name pv.Geo.scale.prototype.domain
179
- * @param {...} domain... domain values.
180
- * @returns {pv.Geo.scale} <tt>this</tt>, or the current domain.
181
- */
182
- scale.domain = function(array, f) {
183
- if (arguments.length) {
184
- d = (array instanceof Array)
185
- ? ((arguments.length > 1) ? pv.map(array, f) : array)
186
- : Array.prototype.slice.call(arguments);
187
- if (d.length > 1) {
188
- var lngs = d.map(function(c) { return c.lng; });
189
- var lats = d.map(function(c) { return c.lat; });
190
- c = {
191
- lng: (pv.max(lngs) + pv.min(lngs)) / 2,
192
- lat: (pv.max(lats) + pv.min(lats)) / 2
193
- };
194
- var n = d.map(project); // normalized domain
195
- x.domain(n, function(p) { return p.x; });
196
- y.domain(n, function(p) { return p.y; });
197
- } else {
198
- c = {lng: 0, lat: 0};
199
- x.domain(-1, 1);
200
- y.domain(-1, 1);
201
- }
202
- lastLatLng = null; // invalidate the cache
203
- return this;
204
- }
205
- return d;
206
- };
207
-
208
- /**
209
- * Sets or gets the output range. This method can be invoked several ways:
210
- *
211
- * <p>1. <tt>range(min, max)</tt>
212
- *
213
- * <p>If two objects are specified, the arguments should be {@link pv.Vector}s
214
- * which specify the minimum and maximum values of the x- and y-coordinates
215
- * explicitly.
216
- *
217
- * <p>2. <tt>range(width, height)</tt>
218
- *
219
- * <p>If two numbers are specified, the arguments specify the maximum values
220
- * of the x- and y-coordinates explicitly; the minimum values are implicitly
221
- * zero.
222
- *
223
- * <p>3. <tt>range()</tt>
224
- *
225
- * <p>Invoking the <tt>range</tt> method with no arguments returns the current
226
- * range as an array of two {@link pv.Vector}s: the minimum (top-left) and
227
- * maximum (bottom-right) values.
228
- *
229
- * @function
230
- * @name pv.Geo.scale.prototype.range
231
- * @param {...} range... range values.
232
- * @returns {pv.Geo.scale} <tt>this</tt>, or the current range.
233
- */
234
- scale.range = function(min, max) {
235
- if (arguments.length) {
236
- if (typeof min == "object") {
237
- rmin = {x: Number(min.x), y: Number(min.y)};
238
- rmax = {x: Number(max.x), y: Number(max.y)};
239
- } else {
240
- rmin = {x: 0, y: 0};
241
- rmax = {x: Number(min), y: Number(max)};
242
- }
243
- x.range(rmin.x, rmax.x);
244
- y.range(rmax.y, rmin.y); // XXX flipped?
245
- lastLatLng = null; // invalidate the cache
246
- return this;
247
- }
248
- return [rmin, rmax];
249
- };
250
-
251
- /**
252
- * Sets or gets the projection. This method can be invoked several ways:
253
- *
254
- * <p>1. <tt>projection(string)</tt>
255
- *
256
- * <p>Specifying a string sets the projection to the given named projection in
257
- * {@link pv.Geo.projections}. If no such projection is found, the identity
258
- * projection is used.
259
- *
260
- * <p>2. <tt>projection(object)</tt>
261
- *
262
- * <p>Specifying an object sets the projection to the given custom projection,
263
- * which must implement the <i>forward</i> and <i>inverse</i> methods per the
264
- * {@link pv.Geo.Projection} interface.
265
- *
266
- * <p>3. <tt>projection()</tt>
267
- *
268
- * <p>Invoking the <tt>projection</tt> method with no arguments returns the
269
- * current object that defined the projection.
270
- *
271
- * @function
272
- * @name pv.Scale.geo.prototype.projection
273
- * @param {...} range... range values.
274
- * @returns {pv.Scale.geo} <tt>this</tt>, or the current range.
275
- */
276
- scale.projection = function(p) {
277
- if (arguments.length) {
278
- j = typeof p == "string"
279
- ? pv.Geo.projections[p] || pv.Geo.projections.identity
280
- : p;
281
- return this.domain(d); // recompute normalized domain
282
- }
283
- return p;
284
- };
285
-
286
- /**
287
- * Returns a view of this scale by the specified accessor function <tt>f</tt>.
288
- * Given a scale <tt>g</tt>, <tt>g.by(function(d) d.foo)</tt> is equivalent to
289
- * <tt>function(d) g(d.foo)</tt>. This method should be used judiciously; it
290
- * is typically more clear to invoke the scale directly, passing in the value
291
- * to be scaled.
292
- *
293
- * @function
294
- * @name pv.Geo.scale.prototype.by
295
- * @param {function} f an accessor function.
296
- * @returns {pv.Geo.scale} a view of this scale by the specified accessor
297
- * function.
298
- */
299
- scale.by = function(f) {
300
- function by() { return scale(f.apply(this, arguments)); }
301
- for (var method in scale) by[method] = scale[method];
302
- return by;
303
- };
304
-
305
- if (arguments.length) scale.projection(p);
306
- return scale;
307
- };