2 nv.models.ohlcBar = function() {
4 //============================================================
5 // Public Variables with Default Settings
6 //------------------------------------------------------------
8 var margin = {top: 0, right: 0, bottom: 0, left: 0}
11 , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one
12 , x = d3.scale.linear()
13 , y = d3.scale.linear()
14 , getX = function(d) { return d.x }
15 , getY = function(d) { return d.y }
16 , getOpen = function(d) { return d.open }
17 , getClose = function(d) { return d.close }
18 , getHigh = function(d) { return d.high }
19 , getLow = function(d) { return d.low }
22 , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart
24 , color = nv.utils.defaultColor()
29 , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout')
32 //============================================================
34 //============================================================
36 //------------------------------------------------------------
38 //TODO: store old scales for transitions
40 //============================================================
43 function chart(selection) {
44 selection.each(function(data) {
45 var availableWidth = width - margin.left - margin.right,
46 availableHeight = height - margin.top - margin.bottom,
47 container = d3.select(this);
50 //------------------------------------------------------------
53 x .domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) ));
56 x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]);
58 x.range(xRange || [0, availableWidth]);
60 y .domain(yDomain || [
61 d3.min(data[0].values.map(getLow).concat(forceY)),
62 d3.max(data[0].values.map(getHigh).concat(forceY))
64 .range(yRange || [availableHeight, 0]);
66 // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point
67 if (x.domain()[0] === x.domain()[1])
69 x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01])
72 if (y.domain()[0] === y.domain()[1])
74 y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01])
77 //------------------------------------------------------------
80 //------------------------------------------------------------
81 // Setup containers and skeleton of chart
83 var wrap = d3.select(this).selectAll('g.nv-wrap.nv-ohlcBar').data([data[0].values]);
84 var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-ohlcBar');
85 var defsEnter = wrapEnter.append('defs');
86 var gEnter = wrapEnter.append('g');
87 var g = wrap.select('g');
89 gEnter.append('g').attr('class', 'nv-ticks');
91 wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
93 //------------------------------------------------------------
97 .on('click', function(d,i) {
107 defsEnter.append('clipPath')
108 .attr('id', 'nv-chart-clip-path-' + id)
111 wrap.select('#nv-chart-clip-path-' + id + ' rect')
112 .attr('width', availableWidth)
113 .attr('height', availableHeight);
115 g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : '');
119 var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick')
120 .data(function(d) { return d });
122 ticks.exit().remove();
125 var ticksEnter = ticks.enter().append('path')
126 .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i })
127 .attr('d', function(d,i) {
128 var w = (availableWidth / data[0].values.length) * .9;
137 + (y(getLow(d,i)) - y(getOpen(d,i)))
147 .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
148 //.attr('fill', function(d,i) { return color[0]; })
149 //.attr('stroke', function(d,i) { return color[0]; })
151 //.attr('y', function(d,i) { return y(Math.max(0, getY(d,i))) })
152 //.attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) })
153 .on('mouseover', function(d,i) {
154 d3.select(this).classed('hover', true);
155 dispatch.elementMouseover({
158 pos: [x(getX(d,i)), y(getY(d,i))], // TODO: Figure out why the value appears to be shifted
165 .on('mouseout', function(d,i) {
166 d3.select(this).classed('hover', false);
167 dispatch.elementMouseout({
175 .on('click', function(d,i) {
176 dispatch.elementClick({
181 pos: [x(getX(d,i)), y(getY(d,i))],
185 d3.event.stopPropagation();
187 .on('dblclick', function(d,i) {
188 dispatch.elementDblClick({
193 pos: [x(getX(d,i)), y(getY(d,i))],
197 d3.event.stopPropagation();
201 .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i })
203 .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; })
204 .attr('d', function(d,i) {
205 var w = (availableWidth / data[0].values.length) * .9;
225 //.attr('width', (availableWidth / data[0].values.length) * .9 )
228 //d3.transition(ticks)
229 //.attr('y', function(d,i) { return y(Math.max(0, getY(d,i))) })
230 //.attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) });
231 //.order(); // not sure if this makes any sense for this model
239 //============================================================
240 // Expose Public Variables
241 //------------------------------------------------------------
243 chart.dispatch = dispatch;
245 chart.options = nv.utils.optionsFunc.bind(chart);
247 chart.x = function(_) {
248 if (!arguments.length) return getX;
253 chart.y = function(_) {
254 if (!arguments.length) return getY;
259 chart.open = function(_) {
260 if (!arguments.length) return getOpen;
265 chart.close = function(_) {
266 if (!arguments.length) return getClose;
271 chart.high = function(_) {
272 if (!arguments.length) return getHigh;
277 chart.low = function(_) {
278 if (!arguments.length) return getLow;
283 chart.margin = function(_) {
284 if (!arguments.length) return margin;
285 margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
286 margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
287 margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
288 margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
292 chart.width = function(_) {
293 if (!arguments.length) return width;
298 chart.height = function(_) {
299 if (!arguments.length) return height;
304 chart.xScale = function(_) {
305 if (!arguments.length) return x;
310 chart.yScale = function(_) {
311 if (!arguments.length) return y;
316 chart.xDomain = function(_) {
317 if (!arguments.length) return xDomain;
322 chart.yDomain = function(_) {
323 if (!arguments.length) return yDomain;
328 chart.xRange = function(_) {
329 if (!arguments.length) return xRange;
334 chart.yRange = function(_) {
335 if (!arguments.length) return yRange;
340 chart.forceX = function(_) {
341 if (!arguments.length) return forceX;
346 chart.forceY = function(_) {
347 if (!arguments.length) return forceY;
352 chart.padData = function(_) {
353 if (!arguments.length) return padData;
358 chart.clipEdge = function(_) {
359 if (!arguments.length) return clipEdge;
364 chart.color = function(_) {
365 if (!arguments.length) return color;
366 color = nv.utils.getColor(_);
370 chart.id = function(_) {
371 if (!arguments.length) return id;
376 //============================================================