source: Dev/branches/jQueryUI/client/d3/src/chart/bullet.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 6.3 KB
Line 
1// Chart design based on the recommendations of Stephen Few. Implementation
2// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
3// http://projects.instantcognition.com/protovis/bulletchart/
4d3.chart.bullet = function() {
5  var orient = "left", // TODO top & bottom
6      reverse = false,
7      duration = 0,
8      ranges = d3_chart_bulletRanges,
9      markers = d3_chart_bulletMarkers,
10      measures = d3_chart_bulletMeasures,
11      width = 380,
12      height = 30,
13      tickFormat = null;
14
15  // For each small multiple

16  function bullet(g) {
17    g.each(function(d, i) {
18      var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
19          markerz = markers.call(this, d, i).slice().sort(d3.descending),
20          measurez = measures.call(this, d, i).slice().sort(d3.descending),
21          g = d3.select(this);
22
23      // Compute the new x-scale.
24      var x1 = d3.scale.linear()
25          .domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
26          .range(reverse ? [width, 0] : [0, width]);
27
28      // Retrieve the old x-scale, if this is an update.
29      var x0 = this.__chart__ || d3.scale.linear()
30          .domain([0, Infinity])
31          .range(x1.range());
32
33      // Stash the new scale.
34      this.__chart__ = x1;
35
36      // Derive width-scales from the x-scales.
37      var w0 = d3_chart_bulletWidth(x0),
38          w1 = d3_chart_bulletWidth(x1);
39
40      // Update the range rects.
41      var range = g.selectAll("rect.range")
42          .data(rangez);
43
44      range.enter().append("svg:rect")
45          .attr("class", function(d, i) { return "range s" + i; })
46          .attr("width", w0)
47          .attr("height", height)
48          .attr("x", reverse ? x0 : 0)
49        .transition()
50          .duration(duration)
51          .attr("width", w1)
52          .attr("x", reverse ? x1 : 0);
53
54      range.transition()
55          .duration(duration)
56          .attr("x", reverse ? x1 : 0)
57          .attr("width", w1)
58          .attr("height", height);
59
60      // Update the measure rects.
61      var measure = g.selectAll("rect.measure")
62          .data(measurez);
63
64      measure.enter().append("svg:rect")
65          .attr("class", function(d, i) { return "measure s" + i; })
66          .attr("width", w0)
67          .attr("height", height / 3)
68          .attr("x", reverse ? x0 : 0)
69          .attr("y", height / 3)
70        .transition()
71          .duration(duration)
72          .attr("width", w1)
73          .attr("x", reverse ? x1 : 0);
74
75      measure.transition()
76          .duration(duration)
77          .attr("width", w1)
78          .attr("height", height / 3)
79          .attr("x", reverse ? x1 : 0)
80          .attr("y", height / 3);
81
82      // Update the marker lines.
83      var marker = g.selectAll("line.marker")
84          .data(markerz);
85
86      marker.enter().append("svg:line")
87          .attr("class", "marker")
88          .attr("x1", x0)
89          .attr("x2", x0)
90          .attr("y1", height / 6)
91          .attr("y2", height * 5 / 6)
92        .transition()
93          .duration(duration)
94          .attr("x1", x1)
95          .attr("x2", x1);
96
97      marker.transition()
98          .duration(duration)
99          .attr("x1", x1)
100          .attr("x2", x1)
101          .attr("y1", height / 6)
102          .attr("y2", height * 5 / 6);
103
104      // Compute the tick format.
105      var format = tickFormat || x1.tickFormat(8);
106
107      // Update the tick groups.
108      var tick = g.selectAll("g.tick")
109          .data(x1.ticks(8), function(d) {
110            return this.textContent || format(d);
111          });
112
113      // Initialize the ticks with the old scale, x0.
114      var tickEnter = tick.enter().append("svg:g")
115          .attr("class", "tick")
116          .attr("transform", d3_chart_bulletTranslate(x0))
117          .style("opacity", 1e-6);
118
119      tickEnter.append("svg:line")
120          .attr("y1", height)
121          .attr("y2", height * 7 / 6);
122
123      tickEnter.append("svg:text")
124          .attr("text-anchor", "middle")
125          .attr("dy", "1em")
126          .attr("y", height * 7 / 6)
127          .text(format);
128
129      // Transition the entering ticks to the new scale, x1.
130      tickEnter.transition()
131          .duration(duration)
132          .attr("transform", d3_chart_bulletTranslate(x1))
133          .style("opacity", 1);
134
135      // Transition the updating ticks to the new scale, x1.
136      var tickUpdate = tick.transition()
137          .duration(duration)
138          .attr("transform", d3_chart_bulletTranslate(x1))
139          .style("opacity", 1);
140
141      tickUpdate.select("line")
142          .attr("y1", height)
143          .attr("y2", height * 7 / 6);
144
145      tickUpdate.select("text")
146          .attr("y", height * 7 / 6);
147
148      // Transition the exiting ticks to the new scale, x1.
149      tick.exit().transition()
150          .duration(duration)
151          .attr("transform", d3_chart_bulletTranslate(x1))
152          .style("opacity", 1e-6)
153          .remove();
154    });
155    d3.timer.flush();
156  }
157
158  // left, right, top, bottom
159  bullet.orient = function(x) {
160    if (!arguments.length) return orient;
161    orient = x;
162    reverse = orient == "right" || orient == "bottom";
163    return bullet;
164  };
165
166  // ranges (bad, satisfactory, good)
167  bullet.ranges = function(x) {
168    if (!arguments.length) return ranges;
169    ranges = x;
170    return bullet;
171  };
172
173  // markers (previous, goal)
174  bullet.markers = function(x) {
175    if (!arguments.length) return markers;
176    markers = x;
177    return bullet;
178  };
179
180  // measures (actual, forecast)
181  bullet.measures = function(x) {
182    if (!arguments.length) return measures;
183    measures = x;
184    return bullet;
185  };
186
187  bullet.width = function(x) {
188    if (!arguments.length) return width;
189    width = x;
190    return bullet;
191  };
192
193  bullet.height = function(x) {
194    if (!arguments.length) return height;
195    height = x;
196    return bullet;
197  };
198
199  bullet.tickFormat = function(x) {
200    if (!arguments.length) return tickFormat;
201    tickFormat = x;
202    return bullet;
203  };
204
205  bullet.duration = function(x) {
206    if (!arguments.length) return duration;
207    duration = x;
208    return bullet;
209  };
210
211  return bullet;
212};
213
214function d3_chart_bulletRanges(d) {
215  return d.ranges;
216}
217
218function d3_chart_bulletMarkers(d) {
219  return d.markers;
220}
221
222function d3_chart_bulletMeasures(d) {
223  return d.measures;
224}
225
226function d3_chart_bulletTranslate(x) {
227  return function(d) {
228    return "translate(" + x(d) + ",0)";
229  };
230}
231
232function d3_chart_bulletWidth(x) {
233  var x0 = x(0);
234  return function(d) {
235    return Math.abs(x(d) - x0);
236  };
237}
Note: See TracBrowser for help on using the repository browser.