package.src.traces.box.cross_trace_calc.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plotly.js Show documentation
Show all versions of plotly.js Show documentation
The open source javascript graphing library that powers plotly
The newest version!
'use strict';
var Axes = require('../../plots/cartesian/axes');
var Lib = require('../../lib');
var getAxisGroup = require('../../plots/cartesian/constraints').getAxisGroup;
var orientations = ['v', 'h'];
function crossTraceCalc(gd, plotinfo) {
var calcdata = gd.calcdata;
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
for(var i = 0; i < orientations.length; i++) {
var orientation = orientations[i];
var posAxis = orientation === 'h' ? ya : xa;
var boxList = [];
// make list of boxes / candlesticks
// For backward compatibility, candlesticks are treated as if they *are* box traces here
for(var j = 0; j < calcdata.length; j++) {
var cd = calcdata[j];
var t = cd[0].t;
var trace = cd[0].trace;
if(trace.visible === true &&
(trace.type === 'box' || trace.type === 'candlestick') &&
!t.empty &&
(trace.orientation || 'v') === orientation &&
trace.xaxis === xa._id &&
trace.yaxis === ya._id
) {
boxList.push(j);
}
}
setPositionOffset('box', gd, boxList, posAxis);
}
}
function setPositionOffset(traceType, gd, boxList, posAxis) {
var calcdata = gd.calcdata;
var fullLayout = gd._fullLayout;
var axId = posAxis._id;
var axLetter = axId.charAt(0);
var i, j, calcTrace;
var pointList = [];
var shownPts = 0;
// make list of box points
for(i = 0; i < boxList.length; i++) {
calcTrace = calcdata[boxList[i]];
for(j = 0; j < calcTrace.length; j++) {
pointList.push(posAxis.c2l(calcTrace[j].pos, true));
shownPts += (calcTrace[j].pts2 || []).length;
}
}
if(!pointList.length) return;
// box plots - update dPos based on multiple traces
var boxdv = Lib.distinctVals(pointList);
if(posAxis.type === 'category' || posAxis.type === 'multicategory') {
boxdv.minDiff = 1;
}
var dPos0 = boxdv.minDiff / 2;
// check for forced minimum dtick
Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true);
var numKey = traceType === 'violin' ? '_numViolins' : '_numBoxes';
var numTotal = fullLayout[numKey];
var group = fullLayout[traceType + 'mode'] === 'group' && numTotal > 1;
var groupFraction = 1 - fullLayout[traceType + 'gap'];
var groupGapFraction = 1 - fullLayout[traceType + 'groupgap'];
for(i = 0; i < boxList.length; i++) {
calcTrace = calcdata[boxList[i]];
var trace = calcTrace[0].trace;
var t = calcTrace[0].t;
var width = trace.width;
var side = trace.side;
// position coordinate delta
var dPos;
// box half width;
var bdPos;
// box center offset
var bPos;
// half-width within which to accept hover for this box/violin
// always split the distance to the closest box/violin
var wHover;
if(width) {
dPos = bdPos = wHover = width / 2;
bPos = 0;
} else {
dPos = dPos0;
if(group) {
var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation;
var alignmentGroups = fullLayout._alignmentOpts[groupId] || {};
var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {};
var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length;
var num = nOffsetGroups || numTotal;
var shift = nOffsetGroups ? trace._offsetIndex : t.num;
bdPos = dPos * groupFraction * groupGapFraction / num;
bPos = 2 * dPos * (-0.5 + (shift + 0.5) / num) * groupFraction;
wHover = dPos * groupFraction / num;
} else {
bdPos = dPos * groupFraction * groupGapFraction;
bPos = 0;
wHover = dPos;
}
}
t.dPos = dPos;
t.bPos = bPos;
t.bdPos = bdPos;
t.wHover = wHover;
// box/violin-only value-space push value
var pushplus;
var pushminus;
// edge of box/violin
var edge = bPos + bdPos;
var edgeplus;
var edgeminus;
// value-space padding
var vpadplus;
var vpadminus;
// pixel-space padding
var ppadplus;
var ppadminus;
// do we add 5% of both sides (more logic for points beyond box/violin below)
var padded = Boolean(width);
// does this trace show points?
var hasPts = (trace.boxpoints || trace.points) && (shownPts > 0);
if(side === 'positive') {
pushplus = dPos * (width ? 1 : 0.5);
edgeplus = edge;
pushminus = edgeplus = bPos;
} else if(side === 'negative') {
pushplus = edgeplus = bPos;
pushminus = dPos * (width ? 1 : 0.5);
edgeminus = edge;
} else {
pushplus = pushminus = dPos;
edgeplus = edgeminus = edge;
}
if(hasPts) {
var pointpos = trace.pointpos;
var jitter = trace.jitter;
var ms = trace.marker.size / 2;
var pp = 0;
if((pointpos + jitter) >= 0) {
pp = edge * (pointpos + jitter);
if(pp > pushplus) {
// (++) beyond plus-value, use pp
padded = true;
ppadplus = ms;
vpadplus = pp;
} else if(pp > edgeplus) {
// (+), use push-value (it's bigger), but add px-pad
ppadplus = ms;
vpadplus = pushplus;
}
}
if(pp <= pushplus) {
// (->) fallback to push value
vpadplus = pushplus;
}
var pm = 0;
if((pointpos - jitter) <= 0) {
pm = -edge * (pointpos - jitter);
if(pm > pushminus) {
// (--) beyond plus-value, use pp
padded = true;
ppadminus = ms;
vpadminus = pm;
} else if(pm > edgeminus) {
// (-), use push-value (it's bigger), but add px-pad
ppadminus = ms;
vpadminus = pushminus;
}
}
if(pm <= pushminus) {
// (<-) fallback to push value
vpadminus = pushminus;
}
} else {
vpadplus = pushplus;
vpadminus = pushminus;
}
var pos = new Array(calcTrace.length);
for(j = 0; j < calcTrace.length; j++) {
pos[j] = calcTrace[j].pos;
}
trace._extremes[axId] = Axes.findExtremes(posAxis, pos, {
padded: padded,
vpadminus: vpadminus,
vpadplus: vpadplus,
vpadLinearized: true,
// N.B. SVG px-space positive/negative
ppadminus: {x: ppadminus, y: ppadplus}[axLetter],
ppadplus: {x: ppadplus, y: ppadminus}[axLetter],
});
}
}
module.exports = {
crossTraceCalc: crossTraceCalc,
setPositionOffset: setPositionOffset
};