'use strict'; var Lib = require('../../lib'); var _ = Lib._; var Axes = require('../../plots/cartesian/axes'); var alignPeriod = require('../../plots/cartesian/align_period'); var BADNUM = require('../../constants/numerical').BADNUM; function calc(gd, trace) { var xa = Axes.getFromId(gd, trace.xaxis); var ya = Axes.getFromId(gd, trace.yaxis); var tickLen = convertTickWidth(gd, xa, trace); var minDiff = trace._minDiff; trace._minDiff = null; var origX = trace._origX; trace._origX = null; var x = trace._xcalc; trace._xcalc = null; var cd = calcCommon(gd, trace, origX, x, ya, ptFunc); trace._extremes[xa._id] = Axes.findExtremes(xa, x, {vpad: minDiff / 2}); if(cd.length) { Lib.extendFlat(cd[0].t, { wHover: minDiff / 2, tickLen: tickLen }); return cd; } else { return [{t: {empty: true}}]; } } function ptFunc(o, h, l, c) { return { o: o, h: h, l: l, c: c }; } // shared between OHLC and candlestick // ptFunc makes a calcdata point specific to each trace type, from oi, hi, li, ci function calcCommon(gd, trace, origX, x, ya, ptFunc) { var o = ya.makeCalcdata(trace, 'open'); var h = ya.makeCalcdata(trace, 'high'); var l = ya.makeCalcdata(trace, 'low'); var c = ya.makeCalcdata(trace, 'close'); var hasTextArray = Lib.isArrayOrTypedArray(trace.text); var hasHovertextArray = Lib.isArrayOrTypedArray(trace.hovertext); // we're optimists - before we have any changing data, assume increasing var increasing = true; var cPrev = null; var hasPeriod = !!trace.xperiodalignment; var cd = []; for(var i = 0; i < x.length; i++) { var xi = x[i]; var oi = o[i]; var hi = h[i]; var li = l[i]; var ci = c[i]; if(xi !== BADNUM && oi !== BADNUM && hi !== BADNUM && li !== BADNUM && ci !== BADNUM) { if(ci === oi) { // if open == close, look for a change from the previous close if(cPrev !== null && ci !== cPrev) increasing = ci > cPrev; // else (c === cPrev or cPrev is null) no change } else increasing = ci > oi; cPrev = ci; var pt = ptFunc(oi, hi, li, ci); pt.pos = xi; pt.yc = (oi + ci) / 2; pt.i = i; pt.dir = increasing ? 'increasing' : 'decreasing'; // For categoryorder, store low and high pt.x = pt.pos; pt.y = [li, hi]; if(hasPeriod) pt.orig_p = origX[i]; // used by hover if(hasTextArray) pt.tx = trace.text[i]; if(hasHovertextArray) pt.htx = trace.hovertext[i]; cd.push(pt); } else { cd.push({pos: xi, empty: true}); } } trace._extremes[ya._id] = Axes.findExtremes(ya, Lib.concat(l, h), {padded: true}); if(cd.length) { cd[0].t = { labels: { open: _(gd, 'open:') + ' ', high: _(gd, 'high:') + ' ', low: _(gd, 'low:') + ' ', close: _(gd, 'close:') + ' ' } }; } return cd; } /* * find min x-coordinates difference of all traces * attached to this x-axis and stash the result in _minDiff * in all traces; when a trace uses this in its * calc step it deletes _minDiff, so that next calc this is * done again in case the data changed. * also since we need it here, stash _xcalc (and _origX) on the trace */ function convertTickWidth(gd, xa, trace) { var minDiff = trace._minDiff; if(!minDiff) { var fullData = gd._fullData; var ohlcTracesOnThisXaxis = []; minDiff = Infinity; var i; for(i = 0; i < fullData.length; i++) { var tracei = fullData[i]; if(tracei.type === 'ohlc' && tracei.visible === true && tracei.xaxis === xa._id ) { ohlcTracesOnThisXaxis.push(tracei); var origX = xa.makeCalcdata(tracei, 'x'); tracei._origX = origX; var xcalc = alignPeriod(trace, xa, 'x', origX).vals; tracei._xcalc = xcalc; var _minDiff = Lib.distinctVals(xcalc).minDiff; if(_minDiff && isFinite(_minDiff)) { minDiff = Math.min(minDiff, _minDiff); } } } // if minDiff is still Infinity here, set it to 1 if(minDiff === Infinity) minDiff = 1; for(i = 0; i < ohlcTracesOnThisXaxis.length; i++) { ohlcTracesOnThisXaxis[i]._minDiff = minDiff; } } return minDiff * trace.tickwidth; } module.exports = { calc: calc, calcCommon: calcCommon };