Skip to content

Commit

Permalink
Optimise calls to drawing pathLines
Browse files Browse the repository at this point in the history
  • Loading branch information
andredumas committed Dec 28, 2014
1 parent eaec1a1 commit d5cd094
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 139 deletions.
198 changes: 130 additions & 68 deletions dist/techan.js
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,9 @@ module.exports = function(indicatorMixin, accessor_ohlc) { // Injected dependen

module.exports = function(accessor_atrtrailingstop, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
var p = {}, // Container for private, direct access mixed in variables
upLine = plot.pathLine(),
downLine = plot.pathLine();

function atrtrailingstop(g) {
var group = plot.groupSelect(g, plot.dataMapper.array);
Expand All @@ -987,19 +989,25 @@ module.exports = function(accessor_atrtrailingstop, plot, plotMixin) { // Injec
}

atrtrailingstop.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
refresh(g, upLine, downLine);
};

function binder() {
upLine.init(p.accessor.d, p.xScale, p.accessor.up, p.yScale);
downLine.init(p.accessor.d, p.xScale, p.accessor.dn, p.yScale);
}

// Mixin 'superclass' methods and variables
plotMixin(atrtrailingstop, p).plot(accessor_atrtrailingstop());
plotMixin(atrtrailingstop, p).plot(accessor_atrtrailingstop(), binder);
binder();

return atrtrailingstop;
};
};

function refresh(g, accessor, x, y, plot) {
g.selectAll('path.up').attr('d', plot.pathLine(accessor.d, x, accessor.up, y));
g.selectAll('path.down').attr('d', plot.pathLine(accessor.d, x, accessor.dn, y));
function refresh(g, upLine, downLine) {
g.selectAll('path.up').attr('d', upLine);
g.selectAll('path.down').attr('d', downLine);
}
},{}],21:[function(require,module,exports){
'use strict';
Expand Down Expand Up @@ -1430,7 +1438,14 @@ function verticalPathLine(x, range) {

module.exports = function(d3_svg_area, accessor_ichimoku, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
var p = {}, // Container for private, direct access mixed in variables
kumoClip = kumoClipArea(),
kumo = kumoPathArea(),
senkouSpanA = plot.pathLine(),
senkouSpanB = plot.pathLine(),
chikouSpan = plot.pathLine(),
tenkanSen = plot.pathLine(),
kijunsen = plot.pathLine();

function ichimoku(g) {
var group = plot.groupSelect(g, plot.dataMapper.array),
Expand All @@ -1452,54 +1467,62 @@ module.exports = function(d3_svg_area, accessor_ichimoku, plot, plotMixin) { //
}

ichimoku.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
refresh(g, p.yScale);
};

function refresh(g, accessor, x, y, plot) {
g.selectAll('.kumoclipup path').attr('d', clipArea(accessor, x, y, y.range()[1]));
g.selectAll('.kumoclipdown path').attr('d', clipArea(accessor, x, y, y.range()[0]));
g.selectAll('path.kumo.up').attr('d', pathArea(accessor, x, y));
g.selectAll('path.kumo.down').attr('d', pathArea(accessor, x, y));
g.selectAll('path.senkouspana').attr('d', plot.pathLine(accessor.d, x, accessor.sa, y, accessor.pks));
g.selectAll('path.senkouspanb').attr('d', plot.pathLine(accessor.d, x, accessor.sb, y, accessor.pks));

g.selectAll('path.chikouspan').attr('d', plot.pathLine(accessor.d, x, accessor.c, y, negate(accessor.pks)));
g.selectAll('path.tenkansen').attr('d', plot.pathLine(accessor.d, x, accessor.ts, y));
g.selectAll('path.kijunsen').attr('d', plot.pathLine(accessor.d, x, accessor.ks, y));
function refresh(g, y) {
g.selectAll('.kumoclipup path').attr('d', kumoClip.y1(y.range()[1])); // Fill the top of the cloud to be clipped
g.selectAll('.kumoclipdown path').attr('d', kumoClip.y1(y.range()[0])); // Fill the bottom of the cloud to be clipped
g.selectAll('path.kumo.up').attr('d', kumo);
g.selectAll('path.kumo.down').attr('d', kumo);
g.selectAll('path.senkouspana').attr('d', senkouSpanA);
g.selectAll('path.senkouspanb').attr('d', senkouSpanB);

g.selectAll('path.chikouspan').attr('d', chikouSpan);
g.selectAll('path.tenkansen').attr('d', tenkanSen);
g.selectAll('path.kijunsen').attr('d', kijunsen);
}

function clipArea(accessor, x, y, top) {
return d3_svg_area()
.defined(function(d) { return accessor.sb(d) !== null; })
.x(function(d) { return x(accessor.d(d), accessor.pks(d)); } )
.y0(function(d) { return y(accessor.sb(d)); } )
.y1(top);
function binder() {
senkouSpanA.init(p.accessor.d, p.xScale, p.accessor.sa, p.yScale, p.accessor.pks);
senkouSpanB.init(p.accessor.d, p.xScale, p.accessor.sb, p.yScale, p.accessor.pks);
chikouSpan .init(p.accessor.d, p.xScale, p.accessor.c, p.yScale, negate(p.accessor.pks));
tenkanSen .init(p.accessor.d, p.xScale, p.accessor.ts, p.yScale);
kijunsen .init(p.accessor.d, p.xScale, p.accessor.ks, p.yScale);
}

function pathArea(accessor, x, y) {
return d3_svg_area()
.defined(function(d) { return accessor.sa(d) !== null && accessor.sb(d) !== null; })
.x(function(d) { return x(accessor.d(d), accessor.pks(d)); } )
.y0(function(d) { return y(accessor.sa(d)); } )
.y1(function(d) { return y(accessor.sb(d)); } );
}

function negate(accessor) {
return function(d) {
return -accessor(d);
};
function kumoClipArea() {
return d3_svg_area().interpolate('monotone')
.defined(function(d) { return p.accessor.sb(d) !== null; })
.x(function(d) { return p.xScale(p.accessor.d(d), p.accessor.pks(d)); } )
.y0(function(d) { return p.yScale(p.accessor.sb(d)); } );
}

function randomID() {
return Math.random().toString(36).substr(2, 9);
function kumoPathArea() {
return d3_svg_area().interpolate('monotone')
.defined(function(d) { return p.accessor.sa(d) !== null && p.accessor.sb(d) !== null; })
.x(function(d) { return p.xScale(p.accessor.d(d), p.accessor.pks(d)); } )
.y0(function(d) { return p.yScale(p.accessor.sa(d)); } )
.y1(function(d) { return p.yScale(p.accessor.sb(d)); } );
}

// Mixin 'superclass' methods and variables
plotMixin(ichimoku, p).plot(accessor_ichimoku());
plotMixin(ichimoku, p).plot(accessor_ichimoku(), binder);
binder();

return ichimoku;
};
};

function negate(accessor) {
return function(d) {
return -accessor(d);
};
}

function randomID() {
return Math.random().toString(36).substr(2, 9);
}
},{}],25:[function(require,module,exports){
'use strict';

Expand Down Expand Up @@ -1543,7 +1566,8 @@ module.exports = function(accessor_value, plot, plotMixin, showZero) { // Injec
showZero = showZero || false;

return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
var p = {}, // Container for private, direct access mixed in variables
svgLine = plot.pathLine();

function line(g) {
var group = plot.groupSelect(g, plot.dataMapper.array);
Expand All @@ -1558,18 +1582,23 @@ module.exports = function(accessor_value, plot, plotMixin, showZero) { // Injec
}

line.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot, showZero);
refresh(g, p.accessor, p.xScale, p.yScale, plot, svgLine, showZero);
};

function binder() {
svgLine.init(p.accessor.d, p.xScale, p.accessor, p.yScale);
}

// Mixin 'superclass' methods and variables
plotMixin(line, p).plot(accessor_value());
plotMixin(line, p).plot(accessor_value(), binder);
binder();

return line;
};
};

function refresh(g, accessor, x, y, plot, showZero) {
g.selectAll('path.line').attr('d', plot.pathLine(accessor.d, x, accessor, y));
function refresh(g, accessor, x, y, plot, svgLine, showZero) {
g.selectAll('path.line').attr('d', svgLine);

if(showZero) {
g.selectAll('path.zero').attr('d', plot.horizontalPathLine(x, accessor.z, y));
Expand All @@ -1580,7 +1609,9 @@ function refresh(g, accessor, x, y, plot, showZero) {

module.exports = function(accessor_macd, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
var p = {}, // Container for private, direct access mixed in variables
macdLine = plot.pathLine(),
signalLine = plot.pathLine();

function macd(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
Expand All @@ -1600,21 +1631,27 @@ module.exports = function(accessor_macd, plot, plotMixin) { // Injected depende
}

macd.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
refresh(g, p.accessor, p.xScale, p.yScale, plot, macdLine, signalLine);
};

function binder() {
macdLine.init(p.accessor.d, p.xScale, p.accessor.m, p.yScale);
signalLine.init(p.accessor.d, p.xScale, p.accessor.s, p.yScale);
}

// Mixin 'superclass' methods and variables
plotMixin(macd, p).plot(accessor_macd());
plotMixin(macd, p).plot(accessor_macd(), binder);
binder();

return macd;
};
};

function refresh(g, accessor, x, y, plot) {
function refresh(g, accessor, x, y, plot, macdLine, signalLine) {
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));
g.selectAll('path.macd').attr('d', macdLine);
g.selectAll('path.signal').attr('d', signalLine);
}

function differencePath(accessor, x, y) {
Expand Down Expand Up @@ -1693,6 +1730,26 @@ module.exports = function(d3_svg_line, d3_select) {
return dataSelection.enter().append('g').attr('class', 'data');
}

function PathLine() {
var d3Line = d3_svg_line().interpolate('monotone');

function line(data) {
return d3Line(data);
}

line.init = function(accessor_date, x, accessor_value, y, offset) {
return d3Line.defined(function(d) { return accessor_value(d) !== null; })
.x(function(d) { return x(accessor_date(d), offset === undefined ? offset : offset(d)); } )
.y(function(d) { return y(accessor_value(d)); } );
};

line.d3 = function() {
return d3Line;
};

return line;
}

return {
dataMapper: {
unity: function(d) { return d; },
Expand Down Expand Up @@ -1731,12 +1788,7 @@ module.exports = function(d3_svg_line, d3_select) {
};
},

pathLine: function(accessor_date, x, accessor_value, y, offset) {
return d3_svg_line().interpolate('monotone')
.defined(function(d) { return accessor_value(d) !== null; })
.x(function(d) { return x(accessor_date(d), offset === undefined ? offset : offset(d)); } )
.y(function(d) { return y(accessor_value(d)); } );
},
pathLine: PathLine,

interaction: {
mousedispatch: function(dispatch) {
Expand Down Expand Up @@ -1825,45 +1877,49 @@ module.exports = function(d3_scale_linear, techan_scale_financetime) {
return function(source, priv) {
var plotMixin = {};

plotMixin.xScale = function() {
plotMixin.xScale = function(binder) {
priv.xScale = techan_scale_financetime();

source.xScale = function(_) {
if (!arguments.length) return priv.xScale;
priv.xScale = _;
if(binder) binder();
return source;
};

return plotMixin;
};

plotMixin.yScale = function() {
plotMixin.yScale = function(binder) {
priv.yScale = d3_scale_linear();

source.yScale = function(_) {
if (!arguments.length) return priv.yScale;
priv.yScale = _;
if(binder) binder();
return source;
};

return plotMixin;
};

plotMixin.accessor = function(accessor) {
plotMixin.accessor = function(accessor, binder) {
priv.accessor = accessor;

source.accessor = function(_) {
if (!arguments.length) return priv.accessor;
priv.accessor = _;
if(binder) binder();
return source;
};

return plotMixin;
};

plotMixin.on = function(dispatch) {
plotMixin.on = function(dispatch, binder) {
source.on = function(type, listener) {
dispatch.on(type, listener);
if(binder) binder();
return source;
};

Expand All @@ -1874,8 +1930,8 @@ module.exports = function(d3_scale_linear, techan_scale_financetime) {
* Generic mixin used for most plots
* @returns {plotMixin}
*/
plotMixin.plot = function(accessor) {
return plotMixin.xScale().yScale().accessor(accessor);
plotMixin.plot = function(accessor, binder) {
return plotMixin.xScale(binder).yScale(binder).accessor(accessor, binder);
};

return plotMixin;
Expand All @@ -1886,7 +1942,8 @@ module.exports = function(d3_scale_linear, techan_scale_financetime) {

module.exports = function(accessor_rsi, plot, plotMixin) { // Injected dependencies
return function() { // Closure function
var p = {}; // Container for private, direct access mixed in variables
var p = {}, // Container for private, direct access mixed in variables
rsiLine = plot.pathLine();

function rsi(g) {
var group = plot.groupSelect(g, plot.dataMapper.array, p.accessor.d);
Expand All @@ -1900,21 +1957,26 @@ module.exports = function(accessor_rsi, plot, plotMixin) { // Injected dependen
}

rsi.refresh = function(g) {
refresh(g, p.accessor, p.xScale, p.yScale, plot);
refresh(g, p.accessor, p.xScale, p.yScale, plot, rsiLine);
};

function binder() {
rsiLine.init(p.accessor.d, p.xScale, p.accessor.r, p.yScale);
}

// Mixin 'superclass' methods and variables
plotMixin(rsi, p).plot(accessor_rsi());
plotMixin(rsi, p).plot(accessor_rsi(), binder);
binder();

return rsi;
};
};

function refresh(g, accessor, x, y, plot) {
function refresh(g, accessor, x, y, plot, rsiLine) {
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));
g.selectAll('path.rsi').attr('d', rsiLine);
}
},{}],32:[function(require,module,exports){
'use strict';
Expand Down
4 changes: 2 additions & 2 deletions dist/techan.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/techan.min.js.map

Large diffs are not rendered by default.

Loading

0 comments on commit d5cd094

Please sign in to comment.