-
Notifications
You must be signed in to change notification settings - Fork 533
/
candlestick.js
109 lines (90 loc) · 3.04 KB
/
candlestick.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
'use strict';
module.exports = function(d3_scale_linear, d3_extent, accessor_ohlc, plot, plotMixin) { // Injected dependencies
return function() { // Closure constructor
var p = {}, // Container for private, direct access mixed in variables
volumeOpacity = false;
function candlestick(g) {
var group = plot.groupSelect(g, plot.dataMapper.unity, p.accessor.d);
// Two path's as wick and body can be styled slightly differently (stroke and fills)
group.entry.append('path').attr('class', 'candle body');
group.entry.append('path').attr('class', 'candle wick');
candlestick.refresh(g);
}
candlestick.refresh = function(g) {
if(volumeOpacity) opacity(g, d3_scale_linear, d3_extent, p.accessor.v);
refresh(g, plot, p.accessor, p.xScale, p.yScale);
};
candlestick.volumeOpacity = function(_) {
if (!arguments.length) return volumeOpacity;
volumeOpacity = _;
return candlestick;
};
// Mixin 'superclass' methods and variables
plotMixin(candlestick, p, accessor_ohlc());
return candlestick;
};
};
function refresh(g, plot, accessor, x, y) {
g.selectAll('path.candle.body').attr('d', bodyPath(accessor, x, y)).classed(plot.classedUpDown(accessor));
g.selectAll('path.candle.wick').attr('d', wickPath(accessor, x, y)).classed(plot.classedUpDown(accessor));
}
function bodyPath(accessor, x, y) {
return function(d) {
var path = [],
open = y(accessor.o(d)),
close = y(accessor.c(d)),
rangeBand = x.band(),
xValue = x(accessor.d(d)) - rangeBand/2;
path.push(
'M', xValue, open,
'l', rangeBand, 0
);
// Draw body only if there is a body (there is no stroke, so will not appear anyway)
if(open != close) {
path.push(
'L', xValue + rangeBand, close,
'l', -rangeBand, 0,
'L', xValue, open
);
}
return path.join(' ');
};
}
function wickPath(accessor, x, y) {
return function(d) {
var path = [],
open = y(accessor.o(d)),
close = y(accessor.c(d)),
rangeBand = x.band(),
xPoint = x(accessor.d(d)),
xValue = xPoint - rangeBand/2;
// Top
path.push(
'M', xPoint, y(accessor.h(d)),
'L', xPoint, Math.min(open, close)
);
// Draw another cross wick if there is no body
if(open == close) {
path.push(
'M', xValue, open,
'l', rangeBand, 0
);
}
// Bottom
path.push(
'M', xPoint, Math.max(open, close),
'L', xPoint, y(accessor.l(d))
);
return path.join(' ');
};
}
function opacity(g, d3_scale_linear, d3_extent, accessor_volume) {
var selection = g.selectAll('g.data'),
volumeOpacityScale = d3_scale_linear()
.domain(d3_extent(selection.data().map(accessor_volume).filter(function(d) { return !isNaN(d); })))
.range([0.2, 1]);
selection.selectAll('path.candle').style('opacity', function(d) {
var volume = accessor_volume(d);
return isNaN(volume) ? null : volumeOpacityScale(volume);
});
}