Skip to content

Instantly share code, notes, and snippets.

@fojt
Created October 20, 2014 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fojt/45fc5fc06d968ce31379 to your computer and use it in GitHub Desktop.
Save fojt/45fc5fc06d968ce31379 to your computer and use it in GitHub Desktop.
Williams %R
Date Open High Low Close Volume
28-Feb-14 69.47 69.88 67.38 68.46 66900863
27-Feb-14 69.34 70.01 68.87 68.94 41695855
26-Feb-14 70.19 71.22 68.85 69.26 55400399
25-Feb-14 70.95 71.00 69.45 69.85 52189031
24-Feb-14 68.74 71.44 68.54 70.78 76951946
21-Feb-14 69.69 69.96 68.45 68.59 70991892
20-Feb-14 67.73 70.11 65.73 69.63 131043748
19-Feb-14 67.05 69.08 67.00 68.06 64258631
18-Feb-14 66.94 67.54 66.07 67.30 43862297
14-Feb-14 67.50 67.58 66.72 67.09 36786427
13-Feb-14 64.18 67.33 64.05 67.33 62013396
12-Feb-14 64.92 65.06 64.05 64.45 47409857
11-Feb-14 63.75 65.00 63.35 64.85 45746832
10-Feb-14 64.30 64.49 63.47 63.55 43736562
7-Feb-14 62.27 64.57 62.22 64.32 60835746
6-Feb-14 61.46 62.78 61.46 62.16 42153754
5-Feb-14 62.74 63.16 61.27 62.19 53032420
4-Feb-14 62.05 63.14 61.82 62.75 46064897
3-Feb-14 63.03 63.77 60.70 61.48 75105994
31-Jan-14 60.47 63.37 60.17 62.57 87930298
30-Jan-14 62.12 62.50 60.46 61.08 150438699
29-Jan-14 54.61 54.95 53.19 53.53 98089932
28-Jan-14 54.02 55.28 54.00 55.14 48364998
27-Jan-14 54.73 54.94 51.85 53.55 74142331
24-Jan-14 56.15 56.42 54.40 54.45 55545338
23-Jan-14 56.37 56.68 55.69 56.63 47996403
22-Jan-14 58.85 59.31 57.10 57.51 61495880
21-Jan-14 56.60 58.58 56.50 58.51 48734147
17-Jan-14 57.30 57.82 56.07 56.30 40883205
16-Jan-14 57.26 58.02 56.83 57.19 34599775
15-Jan-14 57.98 58.57 57.27 57.60 33730619
14-Jan-14 56.46 57.78 56.10 57.74 37590987
13-Jan-14 57.91 58.25 55.38 55.91 63106519
10-Jan-14 57.13 58.30 57.06 57.94 42529258
9-Jan-14 58.65 58.96 56.65 57.22 92349222
8-Jan-14 57.60 58.41 57.23 58.23 56800776
7-Jan-14 57.70 58.55 57.22 57.92 77329009
6-Jan-14 54.42 57.26 54.05 57.20 68974359
3-Jan-14 55.02 55.65 54.53 54.56 38287706
2-Jan-14 54.83 55.22 54.19 54.71 43257622
31-Dec-13 54.12 54.86 53.91 54.65 43152127
30-Dec-13 54.93 55.18 53.43 53.71 68307317
27-Dec-13 57.48 57.68 55.25 55.44 60465751
26-Dec-13 58.32 58.38 57.37 57.73 55101367
24-Dec-13 58.27 58.58 56.91 57.96 46617754
23-Dec-13 55.50 58.32 55.45 57.77 98296983
20-Dec-13 54.91 55.15 54.23 55.12 239823912
19-Dec-13 54.34 55.19 53.95 55.05 89825393
18-Dec-13 55.57 55.89 53.75 55.57 76003479
17-Dec-13 54.75 55.18 54.24 54.86 78751463
16-Dec-13 53.27 54.50 52.91 53.81 85118518
13-Dec-13 51.61 53.50 51.34 53.32 82640992
12-Dec-13 51.03 52.07 50.66 51.83 92723034
11-Dec-13 50.56 50.77 49.01 49.38 65776366
10-Dec-13 48.62 50.77 48.54 50.24 68478561
9-Dec-13 48.06 48.97 47.74 48.84 36055891
6-Dec-13 48.98 49.39 47.71 47.94 42937659
5-Dec-13 48.15 48.70 47.87 48.34 43855036
4-Dec-13 46.46 48.77 46.26 48.62 60890176
3-Dec-13 46.75 47.20 46.29 46.73 32085905
2-Dec-13 46.90 47.54 46.26 47.06 50773647
29-Nov-13 46.75 47.21 46.50 47.01 22953916
27-Nov-13 45.97 46.67 45.53 46.49 44993195
26-Nov-13 44.66 46.17 43.55 45.89 82016490
25-Nov-13 46.36 46.65 44.04 44.82 82565324
22-Nov-13 47.04 47.27 45.96 46.23 40545375
21-Nov-13 46.99 47.46 46.68 46.70 34886170
20-Nov-13 46.61 47.55 46.31 46.43 53932698
19-Nov-13 46.26 47.00 45.72 46.36 75602413
18-Nov-13 48.47 48.84 45.80 45.83 85909884
15-Nov-13 49.11 49.48 48.71 49.01 42452937
14-Nov-13 48.70 49.57 48.03 48.99 75117049
13-Nov-13 46.23 48.74 46.06 48.71 79245346
12-Nov-13 46.00 47.37 45.83 46.60 68195832
11-Nov-13 47.04 47.53 45.73 46.20 80909626
8-Nov-13 47.81 48.65 47.25 47.53 70731178
7-Nov-13 49.24 49.87 47.30 47.56 97127618
6-Nov-13 50.26 50.45 48.71 49.12 67889337
5-Nov-13 47.79 50.18 47.51 50.10 76835006
4-Nov-13 49.36 49.75 48.02 48.22 80371218
1-Nov-13 50.85 52.09 49.72 49.75 95032876
31-Oct-13 47.16 52.00 46.50 50.20 248809006
30-Oct-13 50.00 50.21 48.75 49.01 127072652
29-Oct-13 50.73 50.79 49.25 49.40 102143469
28-Oct-13 51.54 51.70 49.61 50.23 73472347
25-Oct-13 53.18 53.24 51.88 51.95 45085348
24-Oct-13 52.38 52.84 51.59 52.44 46775185
23-Oct-13 51.75 52.25 51.13 51.90 57207154
22-Oct-13 54.33 54.76 52.20 52.68 83203892
21-Oct-13 54.68 54.81 53.51 53.85 58235283
18-Oct-13 54.18 54.82 53.60 54.22 88260093
17-Oct-13 51.12 52.22 50.95 52.21 71521899
16-Oct-13 50.04 51.24 49.90 51.14 64678247
15-Oct-13 49.99 51.00 49.18 49.50 81166571
14-Oct-13 48.31 49.63 47.91 49.51 68780552
11-Oct-13 49.18 49.87 48.79 49.11 58428451
10-Oct-13 47.86 49.68 47.83 49.05 99773784
9-Oct-13 47.38 47.84 45.26 46.77 147296862
8-Oct-13 50.60 50.60 47.08 47.14 136081330
7-Oct-13 50.73 51.29 50.40 50.52 57203957
4-Oct-13 49.77 51.16 49.57 51.04 74446947
3-Oct-13 50.47 50.72 49.06 49.18 82045323
2-Oct-13 50.13 51.10 49.95 50.28 62834429
1-Oct-13 49.97 51.03 49.45 50.42 98113699
30-Sep-13 50.14 51.60 49.80 50.23 100095417
27-Sep-13 50.29 51.28 49.86 51.24 81410460
26-Sep-13 50.01 50.60 49.50 50.39 98220046
25-Sep-13 49.23 49.54 48.46 49.46 87879619
24-Sep-13 48.50 49.66 48.16 48.45 136716101
23-Sep-13 47.28 47.55 46.29 47.19 75319202
20-Sep-13 46.32 47.60 45.74 47.49 115508400
19-Sep-13 45.51 46.05 45.23 45.98 63972369
18-Sep-13 44.84 45.47 44.40 45.23 79316945
17-Sep-13 42.50 45.44 42.43 45.07 91934557
16-Sep-13 44.85 44.94 42.43 42.51 70807761
13-Sep-13 45.04 45.08 43.93 44.31 52765299
12-Sep-13 45.53 45.62 44.65 44.75 68072239
11-Sep-13 43.39 45.09 43.11 45.04 71676653
10-Sep-13 44.24 44.26 43.23 43.60 54540282
9-Sep-13 44.36 44.79 43.70 44.04 75794696
6-Sep-13 43.09 44.61 42.40 43.95 117535626
5-Sep-13 41.79 42.76 41.77 42.66 50035380
4-Sep-13 42.01 42.17 41.44 41.78 42581854
3-Sep-13 41.84 42.16 41.51 41.87 48774896
30-Aug-13 42.02 42.26 41.06 41.29 67735053
29-Aug-13 40.89 41.78 40.80 41.28 58303395
28-Aug-13 39.96 40.85 39.88 40.55 57918194
27-Aug-13 40.68 41.20 39.42 39.64 72695050
26-Aug-13 40.90 41.94 40.62 41.34 94162358
23-Aug-13 39.00 40.63 38.93 40.55 86442283
22-Aug-13 38.37 38.75 38.34 38.55 21931163
21-Aug-13 38.38 38.85 38.14 38.32 46116868
20-Aug-13 38.35 38.58 37.69 38.41 57995140
19-Aug-13 37.43 38.28 37.14 37.81 57609591
16-Aug-13 36.97 37.49 36.90 37.08 45840714
15-Aug-13 36.36 37.07 36.02 36.56 56521095
14-Aug-13 36.83 37.55 36.62 36.65 48423890
13-Aug-13 38.24 38.32 36.77 37.02 65379198
12-Aug-13 38.20 38.50 38.10 38.22 31160951
9-Aug-13 38.59 38.74 38.01 38.50 43620024
8-Aug-13 39.13 39.19 38.43 38.54 41300906
7-Aug-13 38.61 38.94 37.70 38.87 68854764
6-Aug-13 39.11 39.25 37.94 38.55 63950791
5-Aug-13 38.43 39.32 38.25 39.19 79994774
2-Aug-13 37.66 38.49 37.50 38.05 73058424
1-Aug-13 37.30 38.29 36.92 37.49 106066472
31-Jul-13 37.96 38.31 36.33 36.80 154828679
30-Jul-13 35.65 37.96 35.32 37.63 173582710
29-Jul-13 34.07 35.63 34.01 35.43 124884870
26-Jul-13 33.77 34.73 33.56 34.01 136028897
25-Jul-13 33.54 34.88 32.75 34.36 365935212
24-Jul-13 26.32 26.53 26.05 26.51 82635587
23-Jul-13 26.10 26.30 25.97 26.13 28221534
22-Jul-13 25.99 26.13 25.72 26.04 27526213
19-Jul-13 25.82 26.11 25.60 25.88 46544938
18-Jul-13 26.75 26.77 26.12 26.18 24806825
17-Jul-13 26.37 26.78 26.30 26.65 21518463
16-Jul-13 26.39 26.75 26.01 26.32 30817554
15-Jul-13 25.93 26.43 25.65 26.28 24233957
12-Jul-13 25.74 25.93 25.55 25.91 16537840
11-Jul-13 25.96 26.00 25.45 25.81 26777354
10-Jul-13 25.58 25.83 25.47 25.80 26721794
9-Jul-13 25.07 25.49 25.03 25.48 30387889
8-Jul-13 24.47 25.04 24.42 24.71 27073983
5-Jul-13 24.65 24.66 24.20 24.37 20229451
3-Jul-13 24.22 24.71 24.15 24.52 10404332
2-Jul-13 24.70 24.77 24.30 24.41 18394008
1-Jul-13 24.97 25.06 24.62 24.81 20582195
28-Jun-13 24.68 24.98 24.42 24.88 96778879
27-Jun-13 24.24 24.84 24.21 24.66 34694013
26-Jun-13 24.51 24.65 23.99 24.16 29890205
25-Jun-13 24.14 24.43 24.04 24.25 24719988
24-Jun-13 23.95 24.11 23.38 23.94 40625948
21-Jun-13 24.59 24.70 24.05 24.53 45826173
20-Jun-13 24.28 24.74 23.65 23.90 42765586
19-Jun-13 24.20 25.19 24.10 24.31 31790525
18-Jun-13 24.09 24.69 24.08 24.21 36709004
17-Jun-13 23.91 24.25 23.75 24.02 33664419
14-Jun-13 23.56 23.89 23.26 23.63 30561387
13-Jun-13 23.72 23.83 23.26 23.73 31189247
12-Jun-13 24.16 24.26 23.58 23.77 26445790
11-Jun-13 24.03 24.35 24.00 24.03 29676383
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.williams path {
fill: none;
stroke-width: 1;
}
.williams.up {
stroke: #006600;
stroke-width: 1.5;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="techan.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
var x = techan.scale.financetime()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var williams = techan.plot.williams()
.xScale(x)
.yScale(y);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(",.3s"));
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var williamsPeriod = 14;
d3.csv("data.csv", function(error, data) {
var accessor = williams.accessor();
data = data.map(function(d) {
// Open, high, low, close generally not required, is being used here to demonstrate colored volume
// bars
return {
date: parseDate(d.Date),
volume: +d.Volume,
open: +d.Open,
high: +d.High,
low: +d.Low,
close: +d.Close
};
}).sort(function(a, b) { return d3.ascending(accessor.d(a), accessor.d(b)); });
var williamsData = techan.indicator.williams()(data.slice(0, williamsPeriod+200));
x.domain(williamsData.map(accessor.d));
y.domain(techan.scale.plot.williams(williamsData.slice(williamsPeriod,williamsPeriod+200), accessor).domain());
svg.append("g")
.datum(williamsData)
.attr("class", "williams")
.call(williams);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("williams");
});
</script>
/*
TechanJS v0.3.0-4
(c) 2014 - 2014 Andre Dumas | https://github.com/andredumas/techan.js
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.techan=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
'use strict';module.exports='0.3.0-4';
},{}],2:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
adx = function(d) { return d.adx; },
plusDi = function(d) { return d.plusDi; },
minusDi = function(d) { return d.minusDi; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.adx = function(_) {
if (!arguments.length) return adx;
adx = _;
return bind();
};
accessor.plusDi = function(_) {
if (!arguments.length) return plusDi;
plusDi = _;
return bind();
};
accessor.minusDi = function(_) {
if (!arguments.length) return minusDi;
minusDi = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.adx = adx;
accessor.plusDi = plusDi;
accessor.minusDi = minusDi;
return accessor;
}
return bind();
};
},{}],3:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
up = function(d) { return d.up; },
down = function(d) { return d.down; },
oscillator = function(d) { return d.oscillator; },
overbought = function(d) { return d.overbought; },
oversold = function(d) { return d.oversold; },
middle = function(d) { return d.middle; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.up = function(_) {
if (!arguments.length) return up;
up = _;
return bind();
};
accessor.down = function(_) {
if (!arguments.length) return down;
down = _;
return bind();
};
accessor.oscillator = function(_) {
if (!arguments.length) return oscillator;
oscillator = _;
return bind();
};
accessor.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return bind();
};
accessor.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return bind();
};
accessor.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.up = up;
accessor.down = down;
accessor.oscillator = oscillator;
accessor.ob = overbought;
accessor.os = oversold;
accessor.m = middle;
return accessor;
}
return bind();
};
},{}],4:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
middle = function(d) { return d.middleBand; },
upper = function(d) { return d.upperBand; },
lower = function(d) { return d.lowerBand; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return bind();
};
accessor.upper = function(_) {
if (!arguments.length) return upper;
upper = _;
return bind();
};
accessor.lower = function(_) {
if (!arguments.length) return lower;
lower = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.middle = middle;
accessor.upper = upper;
accessor.lower = lower;
return accessor;
}
return bind();
};
},{}],5:[function(_dereq_,module,exports){
'use strict';
// TODO Could these be singletons? Generally will be accessing the same data and data structures at the same time
module.exports = function() {
return {
ohlc: _dereq_('./ohlc'),
volume: _dereq_('./volume'),
macd: _dereq_('./macd'),
rsi: _dereq_('./rsi'),
adx: _dereq_('./adx'),
aroon: _dereq_('./aroon'),
stochastic: _dereq_('./stochastic'),
williams: _dereq_('./williams'),
bollinger: _dereq_('./bollinger'),
trendline: _dereq_('./trendline'),
value: _dereq_('./value')
};
};
},{"./adx":2,"./aroon":3,"./bollinger":4,"./macd":6,"./ohlc":7,"./rsi":8,"./stochastic":9,"./trendline":10,"./value":11,"./volume":12,"./williams":13}],6:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
macd = function(d) { return d.macd; },
zero = function(d) { return d.zero; },
signal = function(d) { return d.signal;},
difference = function(d) { return d.difference;};
function accessor(d) {
return accessor.m(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.macd = function(_) {
if (!arguments.length) return macd;
macd = _;
return bind();
};
accessor.signal = function(_) {
if (!arguments.length) return signal;
signal = _;
return bind();
};
accessor.difference = function(_) {
if (!arguments.length) return difference;
difference = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.m = macd;
accessor.s = signal;
accessor.dif = difference;
accessor.z = zero;
return accessor;
}
return bind();
};
},{}],7:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
open = function(d) { return d.open; },
high = function(d) { return d.high; },
low = function(d) { return d.low; },
close = function(d) { return d.close;},
volume = function(d) { return d.volume; };
function accessor(d) {
return accessor.c(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.open = function(_) {
if (!arguments.length) return open;
open = _;
return bind();
};
accessor.high = function(_) {
if (!arguments.length) return high;
high = _;
return bind();
};
accessor.low = function(_) {
if (!arguments.length) return low;
low = _;
return bind();
};
accessor.close = function(_) {
if (!arguments.length) return close;
close = _;
return bind();
};
accessor.volume = function(_) {
if (!arguments.length) return volume;
volume = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.o = open;
accessor.h = high;
accessor.l = low;
accessor.c = close;
accessor.v = volume;
return accessor;
}
return bind();
};
},{}],8:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
rsi = function(d) { return d.rsi; },
overbought = function(d) { return d.overbought; },
oversold = function(d) { return d.oversold; },
middle = function(d) { return d.middle; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.rsi = function(_) {
if (!arguments.length) return rsi;
rsi = _;
return bind();
};
accessor.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return bind();
};
accessor.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return bind();
};
accessor.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.r = rsi;
accessor.ob = overbought;
accessor.os = oversold;
accessor.m = middle;
return accessor;
}
return bind();
};
},{}],9:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
stochasticK = function(d) { return d.stochasticK; },
stochasticD = function(d) { return d.stochasticD; },
overbought = function(d) { return d.overbought; },
oversold = function(d) { return d.oversold; },
middle = function(d) { return d.middle; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.stochasticK = function(_) {
if (!arguments.length) return stochasticK;
stochasticK = _;
return bind();
};
accessor.stochasticD = function(_) {
if (!arguments.length) return stochasticD;
stochasticD = _;
return bind();
};
accessor.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return bind();
};
accessor.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return bind();
};
accessor.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.k = stochasticK;
accessor.sd = stochasticD;
accessor.ob = overbought;
accessor.os = oversold;
accessor.m = middle;
return accessor;
}
return bind();
};
},{}],10:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var startDate = function(d, _) {
if(arguments.length < 2) return d.start.date;
d.start.date = _;
},
startValue = function(d, _) {
if(arguments.length < 2) return d.start.value;
d.start.value = _;
},
endDate = function(d, _) {
if(arguments.length < 2) return d.end.date;
d.end.date = _;
},
endValue = function(d, _) {
if(arguments.length < 2) return d.end.value;
d.end.value = _;
};
function accessor(d) {
return accessor.sv(d);
}
accessor.startDate = function(_) {
if (!arguments.length) return startDate;
startDate = _;
return bind();
};
accessor.startValue = function(_) {
if (!arguments.length) return startValue;
startValue = _;
return bind();
};
accessor.endDate = function(_) {
if (!arguments.length) return endDate;
endDate = _;
return bind();
};
accessor.endValue = function(_) {
if (!arguments.length) return endValue;
endValue = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.sd = startDate;
accessor.sv = startValue;
accessor.ed = endDate;
accessor.ev = endValue;
return accessor;
}
return bind();
};
},{}],11:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
value = function(d, _) {
if(arguments.length < 2) return d.value;
d.value = _;
},
zero = function(d) { return d.zero; };
function accessor(d) {
return accessor.v(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.value = function(_) {
if (!arguments.length) return value;
value = _;
return bind();
};
accessor.zero = function(_) {
if (!arguments.length) return zero;
zero = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.v = value;
accessor.z = zero;
return accessor;
}
return bind();
};
},{}],12:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
volume = function(d) { return d.volume; };
function accessor(d) {
return accessor.v(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.volume = function(_) {
if (!arguments.length) return volume;
volume = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.v = volume;
return accessor;
}
return bind();
};
},{}],13:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var date = function(d) { return d.date; },
williams = function(d) { return d.williams; };
function accessor(d) {
return accessor.r(d);
}
// TODO use d3.rebind to obtain this from 'super class'
accessor.date = function(_) {
if (!arguments.length) return date;
date = _;
return bind();
};
accessor.williams = function(_) {
if (!arguments.length) return williams;
williams = _;
return bind();
};
function bind() {
// TODO These methods will need to know if the variables are functions or values and execute as such
accessor.d = date;
accessor.w = williams;
return accessor;
}
return bind();
};
},{}],14:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc, indicator_ema) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 14;
function indicator(data) {
var plusDmEma = indicator_ema().accessor(indicator.accessor()).period(period).init(),
minusDmEma = indicator_ema().accessor(indicator.accessor()).period(period).init(),
trEma = indicator_ema().accessor(indicator.accessor()).period(period).init(),
adxEma = indicator_ema().accessor(indicator.accessor()).period(period).init();
return data.map(function(d, i) {
if(i < 1) return datum(p.accessor.d(d));
var upMove = data[i].high - data[i-1].high;
var downMove = data[i-1].low - data[i].low;
var plusDM = 0;
if(upMove > downMove && upMove>0){
plusDM = upMove;
}
var minusDM = 0;
if(downMove > upMove && downMove > 0){
minusDM = downMove;
}
var TR = d3.max([(d.high- d.low),Math.abs(d.high - data[i-1].close),Math.abs(d.low - data[i-1].close) ]);
var plusDmAverage = plusDmEma.average(plusDM),
minusDmAverage = minusDmEma.average(minusDM),
trEmaAverage = trEma.average(TR);
if(i>period) {
var plusDi = 100 * plusDmAverage / trEmaAverage,
minusDi = 100 * minusDmAverage / trEmaAverage,
adxValue = 0;
if(plusDi - minusDi !== 0){
adxValue = Math.abs( (plusDi - minusDi)/(plusDi + minusDi) );
}
var adx;
adx = 100 * adxEma.average(adxValue);
if(i >= period*2) {
return datum(p.accessor.d(d), adx, plusDi, minusDi);
}else return datum(p.accessor.d(d));
}else return datum(p.accessor.d(d));
}).filter(function(d) { return d.adx; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, adx, plusDi, minusDi) {
if(plusDi) {
return { date: date, adx: adx, plusDi: plusDi, minusDi: minusDi };
}else{
return { date: date, adx: null, plusDi: null, minusDi: null };
}
}
},{}],15:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 20,
overbought = 70,
middle = 0,
oversold = 30;
function indicator(data) {
return data.map(function(d, i) {
if(i >= (period-1)){
var max = 0;
var maxi = 0;
var min = 10000;
var mini = 0;
for (var j = 0; j < period; j++) {
if(data[i-j].high > max){
max = data[i-j].high;
maxi = j;
}
if(data[i-j].low < min){
min = data[i-j].low;
mini = j;
}
}
var up = ((period-maxi)/period)*100;
var down = ((period-mini)/period)*100;
var oscillator = up - down;
return datum(p.accessor.d(d), up,down, oscillator, middle, overbought, oversold);
}
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.up; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
indicator.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return indicator;
};
indicator.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return indicator;
};
indicator.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, up,down,oscillator, middle, overbought, oversold) {
if(up) return { date: date, up: up,down:down,oscillator:oscillator, middle: middle, overbought: overbought, oversold: oversold };
else return { date: date, up: null,down:null,oscillator:null, middle: null, overbought: null, oversold: null };
}
},{}],16:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc, indicator_ema) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 20,
sdMultiplication = 2;
var sd;
function indicator(data) {
var signalLine = indicator_ema().accessor(indicator.accessor()).period(period).init();
var j;
return data.map(function(d, i) {
var middleBand = signalLine.average(p.accessor(d));
if(i >= period) {
var sum = 0;
for(j = 0;j<period;j++){
sum += (Math.pow( (data[i-j].close - middleBand) ,2 ) );
}
sd = Math.sqrt( sum/period );
var upperBand = middleBand+sdMultiplication*sd,
lowerBand = middleBand-sdMultiplication*sd;
return datum(p.accessor.d(d), middleBand, upperBand, lowerBand);
}
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.middleBand; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
indicator.sdMultiplication = function(_) {
if (!arguments.length) return sdMultiplication;
sdMultiplication = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, middleBand, upperBand, lowerBand) {
if(middleBand) return { date: date, middleBand: middleBand, upperBand: upperBand, lowerBand: lowerBand};
else return { date: date, middleBand: null, upperBand: null, lowerBand: null};
}
},{}],17:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc, alpha_init) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 10,
previous,
alpha,
initialTotal,
initialCount;
function indicator(data) {
indicator.init();
return data.map(ma).filter(function(d) { return d.value; });
}
indicator.init = function() {
previous = null;
alpha = alpha_init(period);
initialTotal = 0;
initialCount = 0;
return indicator;
};
function ma(d, i) {
var value = indicator.average(p.accessor(d));
if (i+1 < period) {
value = null;
}
return { date: p.accessor.d(d), value: value };
}
indicator.average = function(value) {
if(initialCount < period) return (initialTotal += value)/++initialCount;
else {
if(initialCount === period) {
previous = initialTotal/initialCount++;
}
return (previous = previous + alpha*(value-previous));
}
};
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
},{}],18:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
var indicatorMixin = _dereq_('./indicatormixin')(),
accessor = _dereq_('../accessor')(),
sma = _dereq_('./sma')(indicatorMixin, accessor.ohlc),
ema_init = _dereq_('./ema'),
ema = ema_init(indicatorMixin, accessor.ohlc, ema_alpha_init);
return {
ema: ema,
macd: _dereq_('./macd')(indicatorMixin, accessor.ohlc, ema),
rsi: _dereq_('./rsi')(indicatorMixin, accessor.ohlc, ema),
aroon: _dereq_('./aroon')(indicatorMixin, accessor.ohlc),
stochastic: _dereq_('./stochastic')(indicatorMixin, accessor.ohlc, ema),
williams: _dereq_('./williams')(indicatorMixin, accessor.ohlc, ema),
adx: _dereq_('./adx')(indicatorMixin, accessor.ohlc, ema),
bollinger: _dereq_('./bollinger')(indicatorMixin, accessor.ohlc, sma),
sma: _dereq_('./sma')(indicatorMixin, accessor.ohlc),
wilderma: ema_init(indicatorMixin, accessor.ohlc, wilder_alpha_init)
};
};
function ema_alpha_init(period) {
return 2/(period+1);
}
function wilder_alpha_init(period) {
return 1/period;
}
},{"../accessor":5,"./adx":14,"./aroon":15,"./bollinger":16,"./ema":17,"./indicatormixin":19,"./macd":20,"./rsi":21,"./sma":22,"./stochastic":23,"./williams":24}],19:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
return function(source, priv, accessor) {
// Mixin the functions to the source
source.accessor = function(_) {
if (!arguments.length) return accessor;
accessor = _;
return bind();
};
// Add in the private, direct access variables
function bind() {
priv.accessor = accessor;
return source;
}
bind();
};
};
},{}],20:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc, indicator_ema) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
fast = 12,
slow = 26,
signal = 9;
function indicator(data) {
var minFastSlow = Math.max(fast, slow) - 1,
minCount = minFastSlow + signal - 1,
signalLine = indicator_ema().accessor(indicator.accessor()).period(signal).init(),
fastAverage = indicator_ema().accessor(indicator.accessor()).period(fast).init(),
slowAverage = indicator_ema().accessor(indicator.accessor()).period(slow).init();
return data.map(function(d, i) {
slow = fastAverage.average(p.accessor(d));
fast = slowAverage.average(p.accessor(d));
var macd = slow - fast,
signalValue = i >= minFastSlow ? signalLine.average(macd) : null;
if(i >= minCount) return datum(p.accessor.d(d), macd, signalValue, macd - signalValue, 0);
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.macd; });
}
indicator.fast = function(_) {
if (!arguments.length) return fast;
fast = _;
return indicator;
};
indicator.slow = function(_) {
if (!arguments.length) return slow;
slow = _;
return indicator;
};
indicator.signal = function(_) {
if (!arguments.length) return signal;
signal = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, macd, signal, difference, zero) {
if(macd) return { date: date, macd: macd, signal: signal, difference: difference, zero: zero };
else return { date: date, macd: null, signal: null, difference: null, zero: null };
}
},{}],21:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc, indicator_ema) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 14,
overbought = 70,
middle = 50,
oversold = 30;
function indicator(data) {
var lossAverage = indicator_ema().accessor(indicator.accessor()).period(period).init(),
gainAverage = indicator_ema().accessor(indicator.accessor()).period(period).init();
return data.map(function(d, i) {
if(i < 1) return datum(p.accessor.d(d));
var difference = p.accessor(d) - p.accessor(data[i-1]),
averageGain = gainAverage.average(Math.max(difference, 0)),
averageLoss = Math.abs(lossAverage.average(Math.min(difference, 0)));
if(i >= period) {
var rsi = 100 - (100/(1+(averageGain/averageLoss)));
return datum(p.accessor.d(d), rsi, middle, overbought, oversold);
}
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.rsi; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
indicator.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return indicator;
};
indicator.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return indicator;
};
indicator.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, rsi, middle, overbought, oversold) {
if(rsi) return { date: date, rsi: rsi, middle: middle, overbought: overbought, oversold: oversold };
else return { date: date, rsi: null, middle: null, overbought: null, oversold: null };
}
},{}],22:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 10,
samples,
currentIndex,
total;
function indicator(data) {
indicator.init();
return data.map(ma).filter(function(d) { return d.value; });
}
indicator.init = function() {
total = 0;
samples = [];
currentIndex = 0;
return indicator;
};
function ma(d, i) {
var value = indicator.average(p.accessor(d));
if (i+1 < period) value = null;
return { date: p.accessor.d(d), value: value };
}
indicator.average = function(value) {
total += value;
if(samples.length+1 < period) {
samples.push(value);
return total/++currentIndex;
}
else {
if(samples.length < period) {
samples.push(value);
total += value;
}
total -= samples[currentIndex];
samples[currentIndex] = value;
if(++currentIndex === period) {
currentIndex = 0;
}
return total/period;
}
};
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
},{}],23:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 20,
periodD = 3,
overbought = 80,
middle = 50,
oversold = 20;
function indicator(data) {
return data.map(function(d, i) {
if(i >= period+periodD){
var max = [];
var min = [];
var stochasticKBuffer = [];
for (var per = 0; per < periodD; per++) {
max.push(0);
min.push(10000);
stochasticKBuffer.push(0);
}
var stochasticD = 0;
for (var k = 0; k < periodD; k++) {
for (var j = 0; j < period; j++) {
if(data[i-j-k].high > max[k]){
max[k] = data[i-j-k].high;
}
if(data[i-j-k].low < min[k]){
min[k] = data[i-j-k].low;
}
}
var diff = (max[k]-min[k]);
if(diff > 0) {
stochasticKBuffer[k] = ((data[i - k].close - min[k]) / (max[k] - min[k])) * 100;
}else{
stochasticKBuffer[k] = 50;
}
stochasticD +=stochasticKBuffer[k];
}
var stochasticK =stochasticKBuffer[0];// ((d.close-min)/(max-min))*100;
stochasticD /= periodD;
return datum(p.accessor.d(d), stochasticK,stochasticD, middle, overbought, oversold);
}
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.stochasticK; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
indicator.periodD = function(_) {
if (!arguments.length) return periodD;
periodD = _;
return indicator;
};
indicator.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return indicator;
};
indicator.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return indicator;
};
indicator.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, stochasticK,stochasticD, middle, overbought, oversold) {
if(stochasticK) return { date: date, stochasticK: stochasticK,stochasticD:stochasticD, middle: middle, overbought: overbought, oversold: oversold };
else return { date: date, stochasticK: null,stochasticD:null, middle: null, overbought: null, oversold: null };
}
},{}],24:[function(_dereq_,module,exports){
'use strict';
module.exports = function(indicatorMixin, accessor_ohlc) { // Injected dependencies
return function() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
period = 20,
overbought = 80,
middle = 50,
oversold = 20;
function indicator(data) {
return data.map(function(d, i) {
if(i >= period){
var max = 0;
var maxi = 0;
var min = 10000;
var mini = 0;
for (var j = 0; j < period; j++) {
if(data[i-j].high > max){
max = data[i-j].high;
maxi = j;
}
if(data[i-j].low < min){
min = data[i-j].low;
mini = j;
}
}
var williams = ((data[i].close-min)/(max-min))*100;
return datum(p.accessor.d(d), williams, middle, overbought, oversold);
}
else return datum(p.accessor.d(d));
}).filter(function(d) { return d.williams; });
}
indicator.period = function(_) {
if (!arguments.length) return period;
period = _;
return indicator;
};
indicator.overbought = function(_) {
if (!arguments.length) return overbought;
overbought = _;
return indicator;
};
indicator.middle = function(_) {
if (!arguments.length) return middle;
middle = _;
return indicator;
};
indicator.oversold = function(_) {
if (!arguments.length) return oversold;
oversold = _;
return indicator;
};
// Mixin 'superclass' methods and variables
indicatorMixin(indicator, p, accessor_ohlc());
return indicator;
};
};
function datum(date, williams, middle, overbought, oversold) {
if(williams) return { date: date, williams: williams, middle: middle, overbought: overbought, oversold: oversold };
else return { date: date, williams: null, middle: null, overbought: null, oversold: null };
}
},{}],25:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_adx, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function adx(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'adx');
group.entry.append('path').attr('class', 'plusDi');
group.entry.append('path').attr('class', 'minusDi');
adx.refresh(g);
}
adx.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(adx, p, accessor_adx());
return adx;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.adx').attr('d', plot.pathLine(accessor.d, x, accessor.adx, y));
g.selectAll('path.plusDi').attr('d', plot.pathLine(accessor.d, x, accessor.plusDi, y));
g.selectAll('path.minusDi').attr('d', plot.pathLine(accessor.d, x, accessor.minusDi, y));
}
},{}],26:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_aroon, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function aroon(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'overbought');
group.entry.append('path').attr('class', 'oversold');
group.entry.append('path').attr('class', 'aroon oscillator');
group.entry.append('path').attr('class', 'aroon oscillatorArea');
group.entry.append('path').attr('class', 'aroon middle');
group.entry.append('path').attr('class', 'aroon up');
group.entry.append('path').attr('class', 'aroon down');
aroon.refresh(g);
}
aroon.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(aroon, p, accessor_aroon());
return aroon;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.overbought').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.ob, y));
g.selectAll('path.oversold').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.os, y));
g.selectAll('path.aroon.oscillator').attr('d', plot.pathLine(accessor.d, x, accessor.oscillator, y));
g.selectAll('path.aroon.oscillatorArea').attr('d', plot.pathArea(accessor.d, x, accessor.oscillator, y,0));
g.selectAll('path.aroon.middle').attr('d', plot.pathLine(accessor.d, x, accessor.m, y));
g.selectAll('path.aroon.up').attr('d', plot.pathLine(accessor.d, x, accessor.up, y));
g.selectAll('path.aroon.down').attr('d', plot.pathLine(accessor.d, x, accessor.down, y));
}
},{}],27:[function(_dereq_,module,exports){
'use strict';
/**
* TODO Refactor this to techan.plot.annotation.axis()?
*/
module.exports = function(d3_svg_axis, plot) { // Injected dependencies
return function() { // Closure function
var axis = d3_svg_axis(),
format,
point = 4,
height = 14,
width = 50,
translate = [0, 0];
function annotation(g) {
g.selectAll('g.translate').data(plot.dataMapper.array).enter()
.append('g').attr('class', 'translate');
annotation.refresh(g);
}
annotation.refresh = function(g) {
var fmt = format ? format : (axis.tickFormat() ? axis.tickFormat() : axis.scale().tickFormat());
refresh(g, plot, axis, fmt, height, width, point, translate);
};
annotation.axis = function(_) {
if(!arguments.length) return axis;
axis = _;
return annotation;
};
annotation.format = function(_) {
if(!arguments.length) return format;
format = _;
return annotation;
};
annotation.height = function(_) {
if(!arguments.length) return height;
height = _;
return annotation;
};
annotation.width = function(_) {
if(!arguments.length) return width;
width = _;
return annotation;
};
annotation.translate = function(_) {
if(!arguments.length) return translate;
translate = _;
return annotation;
};
return annotation;
};
};
function refresh(g, plot, axis, format, height, width, point, translate) {
var neg = axis.orient() === 'left' || axis.orient() === 'top' ? -1 : 1,
translateSelection = g.select('g.translate'),
dataGroup = plot.groupSelect(translateSelection, filterInvalidValues(axis.scale()));
dataGroup.entry.append('path');
dataGroup.entry.append('text');
translateSelection.attr('transform', 'translate(' + translate[0] + ',' + translate[1] + ')');
dataGroup.selection.selectAll('path').attr('d', backgroundPath(axis, height, width, point, neg));
dataGroup.selection.selectAll('text').text(textValue(format)).call(textAttributes, axis, neg);
}
function filterInvalidValues(scale) {
return function(data) {
var range = scale.range(),
start = range[0],
end = range[range.length - 1];
range = start < end ? [start, end] : [end, start];
return data.filter(function (d) {
if (!d.value) return false;
var value = scale(d.value);
return value && !isNaN(value) && range[0] <= value && value <= range[1];
});
};
}
function textAttributes(text, axis, neg) {
var scale = axis.scale();
switch(axis.orient()) {
case 'left':
case 'right':
text.attr({
x: neg*(Math.max(axis.innerTickSize(), 0) + axis.tickPadding()),
y: textPosition(scale),
dy: '.32em'
}).style('text-anchor', neg < 0 ? 'end' : 'start');
break;
case 'top':
case 'bottom':
text.attr({
x: textPosition(scale),
y: neg*(Math.max(axis.innerTickSize(), 0) + axis.tickPadding()),
dy: neg < 0 ? '0em' : '.72em'
}).style('text-anchor', 'middle');
break;
}
}
function textPosition(scale) {
return function(d) {
return scale(d.value);
};
}
function textValue(format) {
return function(d) {
return format(d.value);
};
}
function backgroundPath(axis, height, width, point, neg) {
return function(d) {
var scale = axis.scale(),
value = scale(d.value),
pt = point;
switch(axis.orient()) {
case 'left':
case 'right':
var h = 0;
if(height/2 < point) pt = height/2;
else h = height/2-point;
return [
'M', 0, value,
'l', neg*axis.innerTickSize(), -pt,
'l', 0, -h,
'l', neg*width, 0,
'l', 0, height,
'l', neg*-width, 0,
'l', 0, -h
].join(' ');
case 'top':
case 'bottom':
var w = 0;
if(width/2 < point) pt = width/2;
else w = width/2-point;
return [
'M', value, 0,
'l', -pt, neg*axis.innerTickSize(),
'l', -w, 0,
'l', 0, neg*height,
'l', width, 0,
'l', 0, neg*-height,
'l', -w, 0
].join(' ');
default: throw "Unsupported axis.orient() = " + axis.orient();
}
};
}
},{}],28:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_bollinger, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function bollinger(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'upper');
group.entry.append('path').attr('class', 'middle');
group.entry.append('path').attr('class', 'lower');
bollinger.refresh(g);
}
bollinger.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(bollinger, p, accessor_bollinger());
return bollinger;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.upper').attr('d', plot.pathLine(accessor.d, x, accessor.upper, y));
g.selectAll('path.middle').attr('d', plot.pathLine(accessor.d, x, accessor.middle, y));
g.selectAll('path.lower').attr('d', plot.pathLine(accessor.d, x, accessor.lower, y));
}
},{}],29:[function(_dereq_,module,exports){
'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);
});
}
},{}],30:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3_select, d3_event, d3_mouse, d3_dispatch, axisannotation, plotMixin) { // Injected dependencies
return function() { // Closure function
var dispatch = d3_dispatch('enter', 'out', 'move'),
xAnnotation = [axisannotation()],
yAnnotation = [axisannotation()],
verticalWireRange,
horizontalWireRange,
change = 0; // Track changes to this object, to know when to redraw
function crosshair(g) {
var group = g.selectAll('g.data.top').data([change], function(d) { return d; }),
groupEnter = group.enter(),
dataEnter = groupEnter.append('g').attr('class', 'data top').style('display', 'none');
group.exit().remove();
dataEnter.append('path').attr('class', 'horizontal wire');
dataEnter.append('path').attr('class', 'vertical wire');
appendAnnotation(dataEnter, d3_select, 'x', xAnnotation);
appendAnnotation(dataEnter, d3_select, 'y', yAnnotation);
g.selectAll('rect').data([0]).enter().append('rect').style({ fill: 'none', 'pointer-events': 'all' });
crosshair.refresh(g);
}
crosshair.refresh = function(g) {
var xRange = xAnnotation[0].axis().scale().range(),
yRange = yAnnotation[0].axis().scale().range(),
group = g.selectAll('g.data'),
mouseSelection = g.selectAll('rect'),
pathVerticalSelection = group.selectAll('path.vertical'),
pathHorizontalSelection = group.selectAll('path.horizontal'),
xAnnotationSelection = group.selectAll('g.axisannotation.x > g'),
yAnnotationSelection = group.selectAll('g.axisannotation.y > g');
mouseSelection.attr({
x: Math.min(xRange[0], xRange[xRange.length-1]),
y: Math.min(yRange[0], yRange[yRange.length-1]),
height: Math.abs(yRange[yRange.length-1] - yRange[0]),
width: Math.abs(xRange[xRange.length-1] - xRange[0])
})
.on('mouseenter', function() {
display(g, 'inline');
dispatch.enter();
})
.on('mouseout', function() {
display(g, 'none');
dispatch.out();
})
.on('mousemove', mousemoveRefresh(d3_select, d3_mouse, dispatch, xAnnotation, yAnnotation,
pathVerticalSelection, pathHorizontalSelection, xAnnotationSelection, yAnnotationSelection,
verticalWireRange, horizontalWireRange)
);
refresh(d3_select, xAnnotation, yAnnotation, pathVerticalSelection, pathHorizontalSelection,
xAnnotationSelection, yAnnotationSelection, verticalWireRange, horizontalWireRange
);
};
crosshair.xAnnotation = function(_) {
if(!arguments.length) return xAnnotation;
xAnnotation = _ instanceof Array ? _ : [_];
change++; // Annotations have changed, increment to trigger a redraw
return crosshair;
};
crosshair.yAnnotation = function(_) {
if(!arguments.length) return yAnnotation;
yAnnotation = _ instanceof Array ? _ : [_];
change++; // Annotations have changed, increment to trigger a redraw
return crosshair;
};
crosshair.verticalWireRange = function(_) {
if(!arguments.length) return verticalWireRange;
verticalWireRange = _;
return crosshair;
};
crosshair.horizontalWireRange = function(_) {
if(!arguments.length) return horizontalWireRange;
horizontalWireRange = _;
return crosshair;
};
// Mixin event listening
plotMixin.on(crosshair, dispatch);
return crosshair;
};
};
function display(g, style) {
g.select('g.data.top').style('display', style);
}
function mousemoveRefresh(d3_select, d3_mouse, dispatch, xAnnotation, yAnnotation, pathVerticalSelection, pathHorizontalSelection,
xAnnotationSelection, yAnnotationSelection, verticalWireRange, horizontalWireRange) {
var event = [new Array(xAnnotation.length), new Array(yAnnotation.length)];
return function() {
var coords = d3_mouse(this),
x = xAnnotation[0].axis().scale(),
y = yAnnotation[0].axis().scale();
refresh(d3_select, xAnnotation, yAnnotation,
pathVerticalSelection.datum(x.invert(coords[0])),
pathHorizontalSelection.datum(y.invert(coords[1])),
xAnnotationSelection.each(updateAnnotationValue(xAnnotation, coords[0], event[0])),
yAnnotationSelection.each(updateAnnotationValue(yAnnotation, coords[1], event[1])),
verticalWireRange, horizontalWireRange
);
dispatch.move(event);
};
}
function refresh(d3_select, xAnnotation, yAnnotation, xPath, yPath,
xAnnotationSelection, yAnnotationSelection,
verticalWireRange, horizontalWireRange) {
var x = xAnnotation[0].axis().scale(),
y = yAnnotation[0].axis().scale();
xPath.attr('d', verticalPathLine(x, verticalWireRange || y.range()));
yPath.attr('d', horizontalPathLine(y, horizontalWireRange || x.range()));
xAnnotationSelection.each(refreshAnnotation(d3_select, xAnnotation));
yAnnotationSelection.each(refreshAnnotation(d3_select, yAnnotation));
}
function horizontalPathLine(y, range) {
return function(d) {
if(!d) return "M 0 0";
var value = y(d);
return ['M', range[0], value, 'L', range[range.length-1], value].join(' ');
};
}
function verticalPathLine(x, range) {
return function(d) {
if(!d) return "M 0 0";
var value = x(d);
return ['M', value, range[0], 'L', value, range[range.length-1]].join(' ');
};
}
function updateAnnotationValue(annotations, value, event) {
return function(d, i) {
event[i] = annotations[i].axis().scale().invert(value);
// d[0] because only ever 1 value for crosshairs
d[0].value = event[i];
};
}
function appendAnnotation(selection, d3_select, clazz, annotation) {
var annotationSelection = selection.append('g').attr('class', 'axisannotation ' + clazz)
.selectAll('g').data(annotation.map(function() { return [{ value: null }]; }));
annotationSelection.enter().append('g').attr('class', function(d, i) { return i; })
.each(function(d, i) { annotation[i](d3_select(this)); });
}
function refreshAnnotation(d3_select, annotation) {
return function(d, i) {
annotation[i].refresh(d3_select(this));
};
}
},{}],31:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3) {
var scale = _dereq_('../scale')(d3),
accessor = _dereq_('../accessor')(),
plot = _dereq_('./plot')(d3.svg.line, d3.select),
plotMixin = _dereq_('./plotmixin')(d3.scale.linear, scale.financetime),
line = _dereq_('./line'),
axisannotation = _dereq_('./axisannotation')(d3.svg.axis, plot);
return {
axisannotation: axisannotation,
candlestick: _dereq_('./candlestick')(d3.scale.linear, d3.extent, accessor.ohlc, plot, plotMixin),
crosshair: _dereq_('./crosshair')(d3.select, d3_event, d3.mouse, d3.dispatch, axisannotation, plotMixin),
ema: line(accessor.value, plot, plotMixin),
ohlc: _dereq_('./ohlc')(d3.scale.linear, d3.extent, accessor.ohlc, plot, plotMixin),
close: line(accessor.ohlc, plot, plotMixin),
volume: _dereq_('./volume')(accessor.volume, plot, plotMixin),
rsi: _dereq_('./rsi')(accessor.rsi, plot, plotMixin),
adx: _dereq_('./adx')(accessor.adx, plot, plotMixin),
aroon: _dereq_('./aroon')(accessor.aroon, plot, plotMixin),
stochastic: _dereq_('./stochastic')(accessor.stochastic, plot, plotMixin),
williams: _dereq_('./williams')(accessor.williams, plot, plotMixin),
bollinger: _dereq_('./bollinger')(accessor.bollinger, plot, plotMixin),
macd: _dereq_('./macd')(accessor.macd, plot, plotMixin),
momentum: line(accessor.value, plot, plotMixin, true),
moneyflow: line(accessor.value, plot, plotMixin, true),
sma: line(accessor.value, plot, plotMixin),
supstance: _dereq_('./supstance')(d3.behavior.drag, d3_event, d3.select, d3.dispatch, accessor.value, plot, plotMixin),
trendline: _dereq_('./trendline')(d3.behavior.drag, d3_event, d3.select, d3.dispatch, accessor.trendline, plot, plotMixin),
wilderma: line(accessor.value, plot, plotMixin)
};
};
function d3_event() {
return d3.event;
}
},{"../accessor":5,"../scale":44,"./adx":25,"./aroon":26,"./axisannotation":27,"./bollinger":28,"./candlestick":29,"./crosshair":30,"./line":32,"./macd":33,"./ohlc":34,"./plot":35,"./plotmixin":36,"./rsi":37,"./stochastic":38,"./supstance":39,"./trendline":40,"./volume":41,"./williams":42}],32:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_value, plot, plotMixin, showZero) { // Injected dependencies
showZero = showZero || false;
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function line(g) {
var group = plot.groupSelect(g, plot.dataMapper.array);
group.entry.append('path').attr('class', 'line');
if(showZero) {
group.selection.append('path').attr('class', 'zero');
}
line.refresh(g);
}
line.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot, showZero);
};
// Mixin 'superclass' methods and variables
plotMixin(line, p, accessor_value());
return line;
};
};
function refresh(g, accessor, x, y, plot, showZero) {
g.selectAll('path.line').attr('d', plot.pathLine(accessor.d, x, accessor, y));
if(showZero) {
g.selectAll('path.zero').attr('d', plot.horizontalPathLine(x, accessor.z, y));
}
}
},{}],33:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_macd, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function macd(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
var histogramSelection = group.selection
.append('g').attr('class', 'difference')
.selectAll('g.difference').data(function(data) { return data; });
histogramSelection.exit().remove();
histogramSelection.enter().append('path').attr('class', 'difference');
group.selection.append('path').attr('class', 'zero');
group.selection.append('path').attr('class', 'macd');
group.selection.append('path').attr('class', 'signal');
macd.refresh(g);
}
macd.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(macd, p, accessor_macd());
return macd;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.difference').attr('d', differencePath(accessor, x, y));
g.selectAll('path.zero').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.z, y));
g.selectAll('path.macd').attr('d', plot.pathLine(accessor.d, x, accessor.m, y));
g.selectAll('path.signal').attr('d', plot.pathLine(accessor.d, x, accessor.s, y));
}
function differencePath(accessor, x, y) {
return function(d) {
var zero = y(0),
height = y(accessor.dif(d)) - zero,
rangeBand = x.band(),
xValue = x(accessor.d(d)) - rangeBand/2;
return [
'M', xValue, zero,
'l', 0, height,
'l', rangeBand, 0,
'l', 0, -height
].join(' ');
};
}
},{}],34:[function(_dereq_,module,exports){
'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
function ohlc(g) {
plot.groupSelect(g, plot.dataMapper.unity, p.accessor.d)
.entry.append('path').attr({ class: 'ohlc' });
ohlc.refresh(g);
}
ohlc.refresh = function(g) {
refresh(g, plot, p.accessor, p.xScale, p.yScale);
};
// Mixin 'superclass' methods and variables
plotMixin(ohlc, p, accessor_ohlc());
return ohlc;
};
};
function refresh(g, plot, accessor, x, y) {
g.selectAll('path.ohlc').attr({ d: ohlcPath(accessor, x, y) }).classed(plot.classedUpDown(accessor));
}
function ohlcPath(accessor, x, y) {
return function(d) {
var open = y(accessor.o(d)),
close = y(accessor.c(d)),
rangeBand = x.band(),
xPoint = x(accessor.d(d)),
xValue = xPoint - rangeBand/2;
return [
'M', xValue, open,
'l', rangeBand/2, 0,
'M', xPoint, y(accessor.h(d)),
'L', xPoint, y(accessor.l(d)),
'M', xPoint, close,
'l', rangeBand/2, 0
].join(' ');
};
}
},{}],35:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3_svg_line, d3_select) {
function dataSelection(g, dataMapper, accessor_date) {
var selection = g.selectAll('g.data').data(dataMapper, accessor_date);
selection.exit().remove();
return selection;
}
function dataEntry(dataSelection) {
return dataSelection.enter().append('g').attr('class', 'data');
}
return {
dataMapper: {
unity: function(d) { return d; },
array: function(d) { return [d]; }
},
dataSelection: dataSelection,
dataEntry: dataEntry,
groupSelect: function(g, dataMapper, accessor_date) {
var selection = dataSelection(g, dataMapper, accessor_date),
entry = dataEntry(selection);
return {
selection: selection,
entry: entry
};
},
classedUpDown: function(accessor) {
return {
up: function(d) { return accessor.o(d) < accessor.c(d); },
down: function(d) { return accessor.o(d) > accessor.c(d); }
};
},
horizontalPathLine: function(accessor_date, x, accessor_value, y) {
return function(d) {
var firstDatum = d[0],
lastDatum = d[d.length-1];
return [
'M', x(accessor_date(firstDatum)), y(accessor_value(firstDatum)),
'L', x(accessor_date(lastDatum)), y(accessor_value(lastDatum))
].join(' ');
};
},
pathLine: function(accessor_date, x, accessor_value, y) {
return d3_svg_line().interpolate('monotone')
.x(function(d) { return x(accessor_date(d)); } )
.y(function(d) { return y(accessor_value(d)); } );
},
pathArea: function(accessor_date, x, accessor_value, y, yBase) {
return d3.svg.area().interpolate('monotone')
.x(function(d) { return x(accessor_date(d)); } )
.y0(function(d) { return y(yBase);})
.y1(function(d) { return y(accessor_value(d)); } );
},
interaction: {
mousedispatch: function(dispatch) {
return function(selection) {
return selection.on('mouseenter', function(d) {
d3_select(this.parentNode).classed('mouseover', true);
dispatch.mouseenter(d);
})
.on('mouseleave', function(d) {
var parentElement = d3_select(this.parentNode);
if(!parentElement.classed('dragging')) {
parentElement.classed('mouseover', false);
dispatch.mouseout(d);
}
})
.on('mousemove', function(d) { dispatch.mousemove(d); });
};
},
dragStartEndDispatch: function(drag, dispatch) {
return drag.on('dragstart', function(d) {
d3_select(this.parentNode.parentNode).classed('dragging', true);
dispatch.dragstart(d);
})
.on('dragend', function(d) {
d3_select(this.parentNode.parentNode).classed('dragging', false);
dispatch.dragend(d);
});
}
}
};
};
},{}],36:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3_scale_linear, techan_scale_financetime) {
function plotMixin(source, priv, accessor) {
var xScale = techan_scale_financetime(),
yScale = d3_scale_linear();
// Mixin the functions to the source
source.accessor = function(_) {
if (!arguments.length) return accessor;
accessor = _;
return bind();
};
source.xScale = function(_) {
if (!arguments.length) return xScale;
xScale = _;
return bind();
};
source.yScale = function(_) {
if (!arguments.length) return yScale;
yScale = _;
return bind();
};
// Add in the private, direct access variables
function bind() {
priv.xScale = xScale;
priv.yScale = yScale;
priv.accessor = accessor;
return source;
}
bind();
return plotMixin;
}
plotMixin.on = function(source, dispatch) {
source.on = function(type, listener) {
dispatch.on(type, listener);
return source;
};
return plotMixin;
};
return plotMixin;
};
},{}],37:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_rsi, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function rsi(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'overbought');
group.entry.append('path').attr('class', 'middle');
group.entry.append('path').attr('class', 'oversold');
group.entry.append('path').attr('class', 'rsi');
rsi.refresh(g);
}
rsi.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(rsi, p, accessor_rsi());
return rsi;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.overbought').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.ob, y));
g.selectAll('path.middle').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.m, y));
g.selectAll('path.oversold').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.os, y));
g.selectAll('path.rsi').attr('d', plot.pathLine(accessor.d, x, accessor.r, y));
}
},{}],38:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_stochastic, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function stochastic(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'overbought');
group.entry.append('path').attr('class', 'oversold');
group.entry.append('path').attr('class', 'stochastic up');
group.entry.append('path').attr('class', 'stochastic down');
stochastic.refresh(g);
}
stochastic.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(stochastic, p, accessor_stochastic());
return stochastic;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.overbought').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.ob, y));
g.selectAll('path.oversold').attr('d', plot.horizontalPathLine(accessor.d, x, accessor.os, y));
g.selectAll('path.stochastic.up').attr('d', plot.pathLine(accessor.d, x, accessor.k, y));
g.selectAll('path.stochastic.down').attr('d', plot.pathLine(accessor.d, x, accessor.sd, y));
}
},{}],39:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3_behavior_drag, d3_event, d3_select, d3_dispatch, accessor_value, plot, plotMixin) { // Injected dependencies
function Supstance() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
dispatch = d3_dispatch('mouseenter', 'mouseout', 'mousemove', 'drag', 'dragstart', 'dragend');
function supstance(g) {
var group = plot.groupSelect(g, plot.dataMapper.unity);
group.entry.append('g').attr('class', 'supstance')
.append('path');
var interaction = group.entry.append('g').attr('class', 'interaction').style({ opacity: 0, fill: 'none' })
.call(plot.interaction.mousedispatch(dispatch));
interaction.append('path').style('stroke-width', 16);
supstance.refresh(g);
}
supstance.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale);
};
supstance.drag = function(g) {
g.selectAll('.interaction path')
.call(dragBody(dispatch, p.accessor, p.xScale, p.yScale));
};
// Mixin 'superclass' methods and variables
plotMixin(supstance, p, accessor_value())
.on(supstance, dispatch);
return supstance;
}
function dragBody(dispatch, accessor, x, y) {
var drag = d3_behavior_drag().origin(function(d) {
return { x: 0, y: y(accessor.v(d)) };
})
.on('drag', function(d) {
accessor.v(d, y.invert(d3_event().y));
refresh(d3_select(this.parentNode.parentNode), accessor, x, y);
dispatch.drag(d);
});
return plot.interaction.dragStartEndDispatch(drag, dispatch);
}
return Supstance;
};
function refresh(g, accessor, x, y) {
g.selectAll('.supstance path').attr('d', supstancePath(accessor, x, y));
g.selectAll('.interaction path').attr('d', supstancePath(accessor, x, y));
}
function supstancePath(accessor, x, y) {
return function(d) {
var path = [],
range = x.range();
path.push('M', range[0], y(accessor.v(d)));
path.push('L', range[range.length-1], y(accessor.v(d)));
return path.join(' ');
};
}
},{}],40:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3_behavior_drag, d3_event, d3_select, d3_dispatch, accessor_trendline, plot, plotMixin) { // Injected dependencies
function Trendline() { // Closure function
var p = {}, // Container for private, direct access mixed in variables
dispatch = d3_dispatch('mouseenter', 'mouseout', 'mousemove', 'drag', 'dragstart', 'dragend');
function trendline(g) {
var group = plot.groupSelect(g, plot.dataMapper.unity),
trendlineGroup = group.entry.append('g').attr('class', 'trendline');
trendlineGroup.append('path').attr('class', 'body');
trendlineGroup.append('circle').attr({ class: 'start', r: 1 });
trendlineGroup.append('circle').attr({ class: 'end', r: 1 });
var interaction = group.entry.append('g').attr('class', 'interaction').style({ opacity: 0, fill: 'none' })
.call(plot.interaction.mousedispatch(dispatch));
interaction.append('path').attr('class', 'body').style('stroke-width', 16);
interaction.append('circle').attr({ class: 'start', r: 8 });
interaction.append('circle').attr({ class: 'end', r: 8 });
trendline.refresh(g);
}
trendline.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale);
};
trendline.drag = function(g) {
g.selectAll('.interaction circle.start')
.call(dragEnd(dispatch, p.accessor, p.accessor.sd, p.xScale, p.accessor.sv, p.yScale));
g.selectAll('.interaction circle.end')
.call(dragEnd(dispatch, p.accessor, p.accessor.ed, p.xScale, p.accessor.ev, p.yScale));
g.selectAll('.interaction path.body')
.call(dragBody(dispatch, p.accessor, p.xScale, p.yScale));
};
// Mixin 'superclass' methods and variables
plotMixin(trendline, p, accessor_trendline())
.on(trendline, dispatch);
return trendline;
}
function dragEnd(dispatch, accessor, accessor_x, x, accessor_y, y) {
var drag = d3_behavior_drag();
drag.origin(function(d) {
return { x: x(accessor_x(d)), y: y(accessor_y(d)) };
})
.on('drag', function(d) {
updateEnd(accessor_x, x, d3_event().x, accessor_y, y, d3_event().y, d);
refresh(d3_select(this.parentNode.parentNode), accessor, x, y);
dispatch.drag(d);
});
return plot.interaction.dragStartEndDispatch(drag, dispatch);
}
function dragBody(dispatch, accessor, x, y) {
var dragStart = {}, // State information, grabs the start coords of the line
drag = d3_behavior_drag();
drag.origin(function(d) {
dragStart.start = { date: x(accessor.sd(d)), value: y(accessor.sv(d)) };
dragStart.end = { date: x(accessor.ed(d)), value: y(accessor.ev(d)) };
return { x: 0, y: 0 };
})
.on('drag', function(d) {
updateEnd(accessor.sd, x, d3_event().x + dragStart.start.date,
accessor.sv, y, d3_event().y + dragStart.start.value,
d);
updateEnd(accessor.ed, x, d3_event().x + dragStart.end.date,
accessor.ev, y, d3_event().y + dragStart.end.value,
d);
refresh(d3_select(this.parentNode.parentNode), accessor, x, y);
dispatch.drag(d);
});
return plot.interaction.dragStartEndDispatch(drag, dispatch);
}
function updateEnd(accessor_x, x, xValue, accessor_y, y, yValue, d) {
var date = x.invert(xValue);
if(date) accessor_x(d, date);
accessor_y(d, y.invert(yValue));
}
return Trendline;
};
function refresh(g, accessor, x, y) {
g.selectAll('.trendline path.body').attr('d', trendlinePath(accessor, x, y));
g.selectAll('.trendline circle.start').attr(trendlineEnd(accessor.sd, x, accessor.sv, y));
g.selectAll('.trendline circle.end').attr(trendlineEnd(accessor.ed, x, accessor.ev, y));
g.selectAll('.interaction path.body').attr('d', trendlinePath(accessor, x, y));
g.selectAll('.interaction circle.start').attr(trendlineEnd(accessor.sd, x, accessor.sv, y));
g.selectAll('.interaction circle.end').attr(trendlineEnd(accessor.ed, x, accessor.ev, y));
}
function trendlinePath(accessor, x, y) {
return function(d) {
var path = [];
path.push('M', x(accessor.sd(d)), y(accessor.sv(d)));
path.push('L', x(accessor.ed(d)), y(accessor.ev(d)));
return path.join(' ');
};
}
function trendlineEnd(accessor_x, x, accessor_y, y) {
return {
cx: function(d) { return x(accessor_x(d)); },
cy: function(d) { return y(accessor_y(d)); }
};
}
},{}],41:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_volume, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function volume(g) {
var group = plot.groupSelect(g, plot.dataMapper.unity, p.accessor.d)
.entry.append('path')
.attr('class', 'volume');
if(p.accessor.o && p.accessor.c) {
group.classed(plot.classedUpDown(p.accessor));
}
volume.refresh(g);
}
volume.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale);
};
// Mixin 'superclass' methods and variables
plotMixin(volume, p, accessor_volume());
return volume;
};
};
function refresh(g, accessor, x, y) {
g.selectAll('path.volume').attr('d', volumePath(accessor, x, y));
}
function volumePath(accessor, x, y) {
return function(d) {
var vol = accessor.v(d);
if(isNaN(vol)) return null;
var zero = y(0),
height = y(vol) - zero,
rangeBand = x.band(),
xValue = x(accessor.d(d)) - rangeBand/2;
return [
'M', xValue, zero,
'l', 0, height,
'l', rangeBand, 0,
'l', 0, -height
].join(' ');
};
}
},{}],42:[function(_dereq_,module,exports){
'use strict';
module.exports = function(accessor_williams, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
function williams(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
group.entry.append('path').attr('class', 'williams up');
williams.refresh(g);
}
williams.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
};
// Mixin 'superclass' methods and variables
plotMixin(williams, p, accessor_williams());
return williams;
};
};
function refresh(g, accessor, x, y, plot) {
g.selectAll('path.williams.up').attr('d', plot.pathLine(accessor.d, x, accessor.w, y));
}
},{}],43:[function(_dereq_,module,exports){
'use strict';
/*
Finance time scale which is not necessarily continuous, is required to be plot continuous. Finance scale
generally contains data points on days where a market is open but no points when closed, such as weekday
and weekends respectively. When plot, is done so without weekend gaps.
*/
module.exports = function(d3_scale_linear, d3_time, d3_bisect, techan_util_rebindCallback, scale_widen, zoomable) { // Injected dependencies
function financetime(index, domain, padding, outerPadding) {
var dateIndexMap,
tickState = { tickFormat: dailyTickMethod[dailyTickMethod.length-1][2] },
band = 3;
index = index || d3_scale_linear();
domain = domain || [new Date(0), new Date(1)];
padding = padding === undefined ? 0.2 : padding;
outerPadding = outerPadding === undefined ? 0.65 : outerPadding;
/**
* Scales the value to domain. If the value is not within the domain, will currently brutally round the data:
* - If before min domain, will round to 1 index value before min domain
* - If after max domain, will round to 1 index value after min domain
* - If within domain, but not mapped to domain value, uses d3.bisect to find nearest domain index
*
* This logic was not required until the domain was being updated and scales re-rendered and this line
* https://github.com/mbostock/d3/blob/abbe1c75c16c3e9cb08b1d0872f4a19890d3bb58/src/svg/axis.js#L107 was causing error.
* New scale generated ticks that old scale did not have, causing error during transform. To avoid error this logic
* was added.
*
* @param x The value to scale
* @returns {*}
*/
function scale(x) {
var mappedIndex = dateIndexMap[+x];
// Make sure the value has been mapped, if not, determine if it's just before, round in, or just after domain
if(mappedIndex === undefined) {
if(domain[0] > x) mappedIndex = -1; // Less than min, round just out of domain
else mappedIndex = d3_bisect(domain, x); // else let bisect determine where in or just after than domain it is
}
return index(mappedIndex);
}
scale.invert = function(y) {
var i = scale.invertToIndex(y);
return i === null ? null : domain[i];
};
scale.invertToIndex = function(y) {
var i = Math.round(index.invert(y));
return domain[i] ? Math.abs(i) : null;
};
/**
* As the underlying structure relies on a full array, ensure the full domain is passed here,
* not just min and max values.
*
* @param _ The full domain array
* @returns {*}
*/
scale.domain = function(_) {
if (!arguments.length) {
var visible = index.domain();
visible = [
Math.ceil(visible[0]), // If min is fraction, it is partially out of view, round up (ceil)
Math.floor(visible[visible.length-1]) // If max is fraction, is partially out of view, round down (floor)
];
return domain.slice(visible[0], visible[visible.length-1]+1); // Grab visible domain, inclusive
}
domain = _;
return applyDomain();
};
function zoomed() {
band = rangeBand(index, domain, padding);
return scale;
}
function domainMap() {
dateIndexMap = lookupIndex(domain);
}
function applyDomain() {
domainMap();
index.domain([0, domain.length-1]);
zoomed();
// Apply outerPadding and widen the outer edges by pulling the domain in to ensure start and end bands are fully visible
index.domain(index.range().map(scale_widen(outerPadding, band)).map(index.invert));
return zoomed();
}
scale.copy = function() {
return financetime(index.copy(), domain, padding, outerPadding);
};
/**
* Equivalent to d3's ordinal.rangeBand(). It could not be named rangeBand as d3 uses the method
* to determine how axis ticks should be rendered. This scale is a hybrid ordinal and linear scale,
* such that scale(x) returns y at center of the band as does d3.scale.linear()(x) does, whereas
* d3.scale.ordinal()(x) returns y at the beginning of the band. When rendering svg axis, d3
* compensates for this checking if rangeBand is defined and compensates as such.
* @returns {number}
*/
scale.band = function() {
return band;
};
scale.outerPadding = function(_) {
if(!arguments.length) return outerPadding;
outerPadding = _;
return applyDomain();
};
scale.padding = function(_) {
if(!arguments.length) return padding;
padding = _;
return applyDomain();
};
scale.zoomable = function() {
return zoomable(index, zoomed);
};
/*
* Ticks based heavily on d3 implementation. Attempted to implement this using composition with d3.time.scale,
* but in the end there were sufficient differences to 'roll my own'.
* - Different base tick steps: millis not required (yet!)
* - State based tick formatting given the non continuous, even steps of ticks
* - Supporting daily and intraday continuous (no gaps) plotting
* https://github.com/mbostock/d3/blob/e03b6454294e1c0bbe3125f787df56c468658d4e/src/time/scale.js#L67
*/
/**
* Generates ticks as continuous as possible against the underlying domain. Where continuous time ticks
* fall on where there is no matching domain (such as weekend or holiday day), it will be replaced with
* the nearest domain datum ahead of the tick to keep close to continuous.
* @param interval
* @param steps
* @returns {*}
*/
scale.ticks = function(interval, steps) {
var visibleDomain = scale.domain();
if(!visibleDomain.length) return []; // Nothing is visible, no ticks to show
var method = interval === undefined ? tickMethod(visibleDomain, 10) :
typeof interval === 'number' ? tickMethod(visibleDomain, interval) : null;
tickState.tickFormat = method ? method[2] : tickMethod(visibleDomain, 10)[2];
if(method) {
interval = method[0];
steps = method[1];
}
if(typeof steps === "undefined"){
return [];
}
var intervalRange = interval.range(visibleDomain[0], +visibleDomain[visibleDomain.length-1]+1, steps);
return intervalRange // Interval, possibly contains values not in domain
.map(domainTicks(visibleDomain)) // Line up interval ticks with domain, possibly adding duplicates
.reduce(sequentialDuplicates, []); // Filter out duplicates, produce new 'reduced' array
};
/**
* NOTE: The type of tick format returned is dependant on ticks that were generated. To obtain the correct
* format for ticks, ensure ticks function is called first, otherwise a default tickFormat will be returned
* which may not be the optimal representation of the current domain state.
* @returns {Function}
*/
scale.tickFormat = function() {
return function(date) {
return tickState.tickFormat(date);
};
};
techan_util_rebindCallback(scale, index, zoomed, 'range', 'interpolate', 'clamp', 'nice');
domainMap();
return zoomed();
}
function rangeBand(linear, domain, padding) {
return (Math.abs(linear(domain.length-1) - linear(0))/Math.max(1, domain.length-1))*(1-padding);
}
var dayFormat = d3_time.format('%b %e'),
yearFormat = d3_time.format.multi([
['%b %Y', function(d) { return d.getMonth(); }],
['%Y', function() { return true; }]
]),
intraDayFormat = d3_time.format.multi([
[":%S", function(d) { return d.getSeconds(); }],
["%I:%M", function(d) { return d.getMinutes(); }],
["%I %p", function(d) { return d.getHours(); }]
]),
genericTickMethod = [d3_time.second, 1, d3_time.format.multi([
[":%S", function(d) { return d.getSeconds(); }],
["%I:%M", function(d) { return d.getMinutes(); }],
["%I %p", function(d) { return d.getHours(); }],
['%b %e', function() { return true; }]
])
];
var dailyStep = 864e5,
dailyTickSteps = [
dailyStep, // 1-day
6048e5, // 1-week
2592e6, // 1-month
7776e6, // 3-month
31536e6 // 1-year
];
var dailyTickMethod = [
[d3_time.day, 1, dayFormat],
[d3_time.monday, 1, dayFormat],
[d3_time.month, 1, yearFormat],
[d3_time.month, 3, yearFormat],
[d3_time.year, 1, yearFormat]
];
var intraDayTickSteps = [
1e3, // 1-second
5e3, // 5-second
15e3, // 15-second
3e4, // 30-second
6e4, // 1-minute
3e5, // 5-minute
9e5, // 15-minute
18e5, // 30-minute
36e5, // 1-hour
108e5, // 3-hour
216e5, // 6-hour
432e5, // 12-hour
864e5 // 1-day
];
var intraDayTickMethod = [
[d3_time.second, 1, intraDayFormat],
[d3_time.second, 5, intraDayFormat],
[d3_time.second, 15, intraDayFormat],
[d3_time.second, 30, intraDayFormat],
[d3_time.minute, 1, intraDayFormat],
[d3_time.minute, 5, intraDayFormat],
[d3_time.minute, 15, intraDayFormat],
[d3_time.minute, 30, intraDayFormat],
[d3_time.hour, 1, intraDayFormat],
[d3_time.hour, 3, intraDayFormat],
[d3_time.hour, 6, intraDayFormat],
[d3_time.hour, 12, intraDayFormat],
[d3_time.day, 1, dayFormat]
];
function tickMethod(visibleDomain, count) {
if(visibleDomain.length == 1) return genericTickMethod; // If we only have 1 to display, show the generic tick method
// Determine whether we're showing daily or intraday data
var intraDay = (visibleDomain[visibleDomain.length-1] - visibleDomain[0])/dailyStep < 1,
tickMethods = intraDay ? intraDayTickMethod : dailyTickMethod,
tickSteps = intraDay ? intraDayTickSteps : dailyTickSteps,
target = (visibleDomain[visibleDomain.length-1] - visibleDomain[0])/count,
i = d3_bisect(tickSteps, target);
return i ? tickMethods[target/tickSteps[i-1] < tickSteps[i]/target ? i-1 : i] : tickMethods[i];
}
function lookupIndex(array) {
var lookup = {};
array.forEach(function(d, i) { lookup[+d] = i; });
return lookup;
}
function domainTicks(visibleDomain) {
var visibleDomainLookup = lookupIndex(visibleDomain); // Quickly lookup index of the domain
return function(d) {
var value = visibleDomainLookup[+d];
if (value !== undefined) return visibleDomain[value];
return visibleDomain[d3_bisect(visibleDomain, d)];
};
}
function sequentialDuplicates(previous, current) {
if(previous.length === 0 || previous[previous.length-1] !== current) previous.push(current);
return previous;
}
return financetime;
};
},{}],44:[function(_dereq_,module,exports){
'use strict';
module.exports = function(d3) {
var zoomable = _dereq_('./zoomable')(),
util = _dereq_('../util')(),
accessors = _dereq_('../accessor')(),
financetime = _dereq_('./financetime')(d3.scale.linear, d3.time, d3.bisect, util.rebindCallback, widen, zoomable);
return {
financetime: financetime,
analysis: {
supstance: function(data, accessor) {
return d3.scale.linear();
},
trendline: function(data, accessor) {
return d3.scale.linear();
}
},
plot: {
time: function(data, accessor) {
accessor = accessor || accessors.value();
return financetime().domain(data.map(accessor.d));
},
percent: function (scale, reference) {
var domain = scale.domain();
reference = reference || domain[0];
return scale.copy().domain([domain[0], domain[domain.length-1]].map(function(d) { return (d-reference)/reference; }));
},
ohlc: function (data, accessor) {
accessor = accessor || accessors.ohlc();
return d3.scale.linear()
.domain([d3.min(data.map(accessor.low())), d3.max(data.map(accessor.high()))].map(widen(0.02)))
.range([1, 0]);
},
volume: function (data, accessor) {
accessor = accessor || accessors.ohlc().v;
return d3.scale.linear()
.domain([0, d3.max(data.map(accessor))*1.15])
.range([1, 0]);
},
rsi: function () {
return d3.scale.linear().domain([0, 100])
.range([1, 0]);
},
adx: function () {
return d3.scale.linear().domain([0, 100])
.range([1, 0]);
},
aroon: function () {
return d3.scale.linear().domain([-100, 100])
.range([1, 0]);
},
stochastic: function () {
return d3.scale.linear().domain([0, 100])
.range([1, 0]);
},
williams: function () {
return d3.scale.linear().domain([0, 100])
.range([1, 0]);
},
bollinger: function (data, accessor) {
accessor = accessor || accessors.bollinger();
return d3.scale.linear()
.domain([
d3.min(data.map(function(d){return accessor.lower(d);})),
d3.max(data.map(function(d){return accessor.upper(d);}))
].map(widen(0.02)))
.range([1, 0]);
},
momentum: function(data, accessor) {
accessor = accessor || accessors.value();
return pathScale(d3, data, accessor, 0.04);
},
moneyflow: function(data, accessor) {
accessor = accessor || accessors.value();
return pathScale(d3, data, accessor, 0.04);
},
macd: function(data, accessor) {
accessor = accessor || accessors.macd();
return pathScale(d3, data, accessor, 0.04);
},
movingaverage: function(data, accessor) {
accessor = accessor || accessors.value();
return pathScale(d3, data, accessor);
}
},
position: {
}
};
};
function pathDomain(d3, data, accessor, widening) {
return data.length > 0 ? d3.extent(data, accessor).map(widen(widening)) : null;
}
function pathScale(d3, data, accessor, widening) {
return d3.scale.linear().domain(pathDomain(d3, data, accessor, widening))
.range([1, 0]);
}
/**
* Only to be used on an array of 2 elements [min, max]
* @param padding
* @param width
* @returns {Function}
*/
function widen(widening, width) {
widening = widening || 0;
return function(d, i, array) {
if(array.length > 2) throw "array.length > 2 unsupported. array.length = " + array.length;
width = width || (array[array.length-1] - array[0]);
return d + (i*2-1)*width*widening;
};
}
},{"../accessor":5,"../util":47,"./financetime":43,"./zoomable":45}],45:[function(_dereq_,module,exports){
'use strict';
/**
* Creates a decorated zoomable view of the passed scale. As the finance scale deals with an array and integer positions within the
* array, it does not support the d3 zoom behaviour. d3 zoom behaviour rescales the input domain.
* Finance scale is composed of an array of dates which is fixed in length and position and a linear scale mapping index
* to range. The linear scale can be zoomed. This object decorates the scale with only the methods required by zoom
* (invert, domain, copy). On zoom, calls the based zoomed callback.
*
* NOTE: This is not a complete scale, it will throw errors if it is used for anything else but zooming
*/
module.exports = function() {
function zoomable(linear, zoomed) {
var scale = {},
domainLimit = linear.domain();
scale.invert = linear.invert;
scale.domain = function(_) {
if(!arguments.length) throw "zoomable is a write only domain. Use this scale for zooming only";
linear.domain([Math.max(domainLimit[0], _[0]), Math.min(domainLimit[1], _[1])]);
if(zoomed) zoomed(); // Callback to that we have been zoomed
return scale;
};
scale.range = function(_) {
if(!arguments.length) return linear.range();
throw "zoomable is a read only range. Use this scale for zooming only";
};
scale.copy = function() {
return zoomable(linear.copy(), zoomed);
};
return scale;
}
return zoomable;
};
},{}],46:[function(_dereq_,module,exports){
'use strict';
module.exports = (function(d3) {
return {
version: _dereq_('../build/version'),
accessor: _dereq_('./accessor')(),
indicator: _dereq_('./indicator')(),
plot: _dereq_('./plot')(d3),
scale: _dereq_('./scale')(d3)
};
})(d3);
},{"../build/version":1,"./accessor":5,"./indicator":18,"./plot":31,"./scale":44}],47:[function(_dereq_,module,exports){
'use strict';
module.exports = function() {
return {
rebindCallback: rebindCallback,
rebind: function(target, source) {
var newArgs = Array.prototype.slice.call(arguments, 0);
newArgs.splice(2, 0, undefined);
return rebindCallback.apply(this, newArgs);
}
};
};
/*
Slight modification to d3.rebind taking a post set callback
https://github.com/mbostock/d3/blob/master/src/core/rebind.js
*/
function rebindCallback(target, source, postSetCallback) {
var i = 2, n = arguments.length, method;
while (++i < n) target[method = arguments[i]] = doRebind(target, source, source[method], postSetCallback);
return target;
}
function doRebind(target, source, method, postSetCallback) {
return function() {
var value = method.apply(source, arguments);
if(postSetCallback && value === source) postSetCallback();
return value === source ? target : value;
};
}
},{}]},{},[46])
(46)
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment