10000 Add spikelines by apalchys · Pull Request #2247 · plotly/plotly.js · GitHub
[go: up one dir, main page]

Skip to content

Add spikelines #2247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jan 17, 2018
Prev Previous commit
Next Next commit
fix issues after PR code review
  • Loading branch information
apalchys committed Jan 17, 2018
commit 6c2f368b796a74172cbc6ed575514307cd4edafe
74 changes: 40 additions & 34 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
return dragElement.unhoverRaw(gd, evt);
}

var hoverdistance = fullLayout.hoverdistance === 0 ? Infinity : fullLayout.hoverdistance;
var spikedistance = fullLayout.spikedistance === 0 ? Infinity : fullLayout.spikedistance;
var hoverdistance = fullLayout.hoverdistance === -1 ? Infinity : fullLayout.hoverdistance;
var spikedistance = fullLayout.spikedistance === -1 ? Infinity : fullLayout.spikedistance;

// hoverData: the set of candidate points we've found to highlight
var hoverData = [],
Expand Down Expand Up @@ -268,17 +268,18 @@ function _hover(gd, evt, subplot, noHoverEvent) {

// [x|y]px: the pixels (from top left) of the mouse location
// on the currently selected plot area
// add pointerX|Y property for drawing the spikes in spikesnap 'cursor' situation
var hasUserCalledHover = !evt.target,
xpx, ypx;

if(hasUserCalledHover) {
if('xpx' in evt) xpx = evt.xpx;
else xpx = xaArray[0]._length / 2;
if(!('offsetX' in evt)) evt.offsetX = xpx + xaArray[0]._offset;
evt.pointerX = xpx + xaArray[0]._offset;

if('ypx' in evt) ypx = evt.ypx;
else ypx = yaArray[0]._length / 2;
if(!('offsetY' in evt)) evt.offsetY = ypx + yaArray[0]._offset;
evt.pointerY = ypx + yaArray[0]._offset;
}
else {
// fire the beforehover event and quit if it returns false
Expand All @@ -298,6 +299,8 @@ function _hover(gd, evt, subplot, noHoverEvent) {
if(xpx < 0 || xpx > dbb.width || ypx < 0 || ypx > dbb.height) {
return dragElement.unhoverRaw(gd, evt);
}
evt.pointerX = evt.offsetX;
evt.pointerY = evt.offsetY;
}

if('xval' in evt) xvalArray = helpers.flat(subplots, evt.xval);
Expand Down Expand Up @@ -391,21 +394,23 @@ function _hover(gd, evt, subplot, noHoverEvent) {
yval = yvalArray[subploti];
}

// Now find the points.
if(trace._module && trace._module.hoverPoints) {
var newPoints = trace._module.hoverPoints(pointData, xval, yval, mode, fullLayout._hoverlayer);
if(newPoints) {
var newPoint;
for(var newPointNum = 0; newPointNum < newPoints.length; newPointNum++) {
newPoint = newPoints[newPointNum];
if(isNumeric(newPoint.x0) && isNumeric(newPoint.y0)) {
hoverData.push(cleanPoint(newPoint, hovermode));
// Now if there is range to look in, find the points to hover.
if(hoverdistance !== 0) {
if(trace._module && trace._module.hoverPoints) {
var newPoints = trace._module.hoverPoints(pointData, xval, yval, mode, fullLayout._hoverlayer);
if(newPoints) {
var newPoint;
for(var newPointNum = 0; newPointNum < newPoints.length; newPointNum++) {
newPoint = newPoints[newPointNum];
if(isNumeric(newPoint.x0) && isNumeric(newPoint.y0)) {
hoverData.push(cleanPoint(newPoint, hovermode));
}
}
}
}
}
else {
Lib.log('Unrecognized trace type in hover:', trace);
else {
Lib.log('Unrecognized trace type in hover:', trace);
}
}

// in closest mode, remove any existing (farther) points
Expand All @@ -415,9 +420,9 @@ function _hover(gd, evt, subplot, noHoverEvent) {
distance = hoverData[0].distance;
}

// Now look for the points to draw the spikelines
// Now if there is range to look in, find the points to draw the spikelines
// Do it only if there is no hoverData
if(fullLayout._has('cartesian')) {
if(fullLayout._has('cartesian') && (spikedistance !== 0)) {
if(hoverData.length === 0) {
pointData.distance = spikedistance;
pointData.index = false;
Expand All @@ -430,7 +435,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
if(closestVPoints.length) {
var closestVPt = closestVPoints[0];
if(isNumeric(closestVPt.x0) && isNumeric(closestVPt.y0)) {
tmpPoint = clearClosestPoint(closestVPt);
tmpPoint = fillClosestPoint(closestVPt);
if(!spikePoints.vLinePoint || (spikePoints.vLinePoint.distance > tmpPoint.distance)) {
spikePoints.vLinePoint = tmpPoint;
}
Expand All @@ -443,7 +448,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
if(closestHPoints.length) {
var closestHPt = closestHPoints[0];
if(isNumeric(closestHPt.x0) && isNumeric(closestHPt.y0)) {
tmpPoint = clearClosestPoint(closestHPt);
tmpPoint = fillClosestPoint(closestHPt);
if(!spikePoints.hLinePoint || (spikePoints.hLinePoint.distance > tmpPoint.distance)) {
spikePoints.hLinePoint = tmpPoint;
}
Expand All @@ -463,7 +468,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
xpx = xa.c2p(xval),
ypx = ya.c2p(yval),
dxy = function(point) {
var rad = Math.max(3, point.mrc || 0),
var rad = point.kink,
dx = (point.x1 + point.x0) / 2 - xpx,
dy = (point.y1 + point.y0) / 2 - ypx;
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
Expand All @@ -486,7 +491,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
return resultPoint;
}

function clearClosestPoint(point) {
function fillClosestPoint(point) {
if(!point) return null;
return {
xa: point.xa,
Expand All @@ -502,7 +507,6 @@ function _hover(gd, evt, subplot, noHoverEvent) {
};
}

// if hoverData is empty check for the spikes to draw and quit if there are none
var spikelineOpts = {
fullLayout: fullLayout,
container: fullLayout._hoverlayer,
Expand All @@ -516,22 +520,24 @@ function _hover(gd, evt, subplot, noHoverEvent) {
};
gd._spikepoints = newspikepoints;

if(fullLayout._has('cartesian')) {
// Now if it is not restricted by spikedistance option, set the points to draw the spikelines
if(fullLayout._has('cartesian') && (spikedistance !== 0)) {
if(hoverData.length !== 0) {
var tmpHPointData = hoverData.filter(function(point) {
return point.ya.showspikes;
});
var tmpHPoint = selectClosestPoint(tmpHPointData, spikedistance);
spikePoints.hLinePoint = clearClosestPoint(tmpHPoint);
spikePoints.hLinePoint = fillClosestPoint(tmpHPoint);

var tmpVPointData = hoverData.filter(function(point) {
return point.xa.showspikes;
});
var tmpVPoint = selectClosestPoint(tmpVPointData, spikedistance);
spikePoints.vLinePoint = clearClosestPoint(tmpVPoint);
spikePoints.vLinePoint = fillClosestPoint(tmpVPoint);
}
}

// if hoverData is empty check for the spikes to draw and quit if there are none
if(hoverData.length === 0) {
var result = dragElement.unhoverRaw(gd, evt);
if(fullLayout._has('cartesian') && ((spikePoints.hLinePoint !== null) || (spikePoints.vLinePoint !== null))) {
Expand Down Expand Up @@ -1228,8 +1234,8 @@ function createSpikelines(closestPoints, opts) {
var xa,
ya;

var showY = closestPoints.hLinePoint ? true : false;
var showX = closestPoints.vLinePoint ? true : false;
var showY = !!closestPoints.hLinePoint;
var showX = !!closestPoints.vLinePoint;

// Remove old spikeline items
container.selectAll('.spikeline').remove();
Expand All @@ -1248,11 +1254,11 @@ function createSpikelines(closestPoints, opts) {
var ySnap = ya.spikesnap;

if(ySnap === 'cursor') {
hLinePointY = evt.offsetY;
hLinePointX = evt.offsetX;
hLinePointX = evt.pointerX;
hLinePointY = evt.pointerY;
} else {
hLinePointY = ya._offset + (hLinePoint.y0 + hLinePoint.y1) / 2;
hLinePointX = xa._offset + (hLinePoint.x0 + hLinePoint.x1) / 2;
hLinePointY = ya._offset + (hLinePoint.y0 + hLinePoint.y1) / 2;
}
var dfltHLineColor = tinycolor.readability(hLinePoint.color, contrastColor) < 1.5 ?
Color.contrast(contrastColor) : hLinePoint.color;
Expand Down Expand Up @@ -1324,8 +1330,8 @@ function createSpikelines(closestPoints, opts) {
var xSnap = xa.spikesnap;

if(xSnap === 'cursor') {
vLinePointX = evt.offsetX;
vLinePointY = evt.offsetY;
vLinePointX = evt.pointerX;
vLinePointY = evt.pointerY;
} else {
vLinePointX = xa._offset + (vLinePoint.x0 + vLinePoint.x1) / 2;
vLinePointY = ya._offset + (vLinePoint.y0 + vLinePoint.y1) / 2;
Expand Down Expand Up @@ -1408,7 +1414,7 @@ function hoverChanged(gd, evt, oldhoverdata) {
}

function spikesChanged(gd, oldspikepoints) {
// don't emit any events if nothing changed
// don't relayout the plot because of new spikelines if spikelines points didn't change
if(!oldspikepoints) return true;
if(oldspikepoints.vLinePoint !== gd._spikepoints.vLinePoint ||
oldspikepoints.hLinePoint !== gd._spikepoints.hLinePoint
Expand Down
16 changes: 8 additions & 8 deletions src/components/fx/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,24 @@ module.exports = {
},
hoverdistance: {
valType: 'integer',
min: 0,
min: -1,
dflt: 20,
role: 'style',
role: 'info',
editType: 'none',
description: [
'Sets the default distance (in points) to look for data',
'to add hover labels (zero means no cutoff)'
'Sets the default distance (in pixels) to look for data',
'to add hover labels (-1 means no cutoff, 0 means no looking for data)'
].join(' ')
},
spikedistance: {
valType: 'integer',
min: 0,
min: -1,
dflt: 20,
role: 'style',
role: 'info',
editType: 'none',
description: [
'Sets the default distance (in points) to look for data to draw',
'spikelines to (zero means no cutoff).'
'Sets the default distance (in pixels) to look for data to draw',
'spikelines to (-1 means no cutoff, 0 means no looking for data).'
].join(' ')
},
hoverlabel: {
Expand Down
8 changes: 5 additions & 3 deletions src/components/fx/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
}
else hovermodeDflt = 'closest';

coerce('hovermode', hovermodeDflt);
coerce('hoverdistance');
coerce('spikedistance');
var hoverMode = coerce('hovermode', hovermodeDflt);
if(hoverMode) {
coerce('hoverdistance');
coerce('spikedistance');
}

// if only mapbox or geo subplots is present on graph,
// reset 'zoom' dragmode to 'pan' until 'zoom' is implemented,
Expand Down
16 changes: 8 additions & 8 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ function handleCartesian(gd, ev) {
var fullLayout = gd._fullLayout;
var aobj = {};
var axList = axisIds.list(gd, null, true);
var allEnabled = 'on';
var allSpikesEnabled = 'on';

var ax, i;

Expand Down Expand Up @@ -209,8 +209,8 @@ function handleCartesian(gd, ev) {
}
if(ax._showSpikeInitial !== undefined) {
aobj[axName + '.showspikes'] = ax._showSpikeInitial;
if(allEnabled === 'on' && !ax._showSpikeInitial) {
allEnabled = 'off';
if(allSpikesEnabled === 'on' && !ax._showSpikeInitial) {
allSpikesEnabled = 'off';
}
}
}
Expand All @@ -230,7 +230,7 @@ function handleCartesian(gd, ev) {
}
}
}
fullLayout._cartesianSpikesEnabled = allEnabled;
fullLayout._cartesianSpikesEnabled = allSpikesEnabled;
}
else {
// if ALL traces have orientation 'h', 'hovermode': 'x' otherwise: 'y'
Expand All @@ -240,11 +240,11 @@ function handleCartesian(gd, ev) {
} else if(astr === 'hovermode' && val === 'closest') {
for(i = 0; i < axList.length; i++) {
ax = axList[i];
if(allEnabled === 'on' && !ax.showspikes) {
allEnabled = 'off';
if(allSpikesEnabled === 'on' && !ax.showspikes) {
allSpikesEnabled = 'off';
}
}
fullLayout._cartesianSpikesEnabled = allEnabled;
fullLayout._cartesianSpikesEnabled = allSpikesEnabled;
}

aobj[astr] = val;
Expand Down Expand Up @@ -566,7 +566,7 @@ function setSpikelineVisibility(gd) {
for(var i = 0; i < axList.length; i++) {
ax = axList[i];
axName = ax._name;
aobj[axName + '.showspikes'] = fullLayout._cartesianSpikesEnabled === 'on' ? true : false;
aobj[axName + '.showspikes'] = fullLayout._cartesianSpikesEnabled === 'on' ? true : ax._showSpikeInitial;
}

return aobj;
Expand Down
8 changes: 4 additions & 4 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ axes.saveRangeInitial = function(gd, overwrite) {
axes.saveShowSpikeInitial = function(gd, overwrite) {
var axList = axes.list(gd, '', true),
hasOneAxisChanged = false,
allEnabled = 'on';
allSpikesEnabled = 'on';

for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
Expand All @@ -415,11 +415,11 @@ axes.saveShowSpikeInitial = function(gd, overwrite) {
hasOneAxisChanged = true;
}

if(allEnabled === 'on' && !ax.showspikes) {
allEnabled = 'off';
if(allSpikesEnabled === 'on' && !ax.showspikes) {
allSpikesEnabled = 'off';
}
}
gd._fullLayout._cartesianSpikesEnabled = allEnabled;
gd._fullLayout._cartesianSpikesEnabled = allSpikesEnabled;
return hasOneAxisChanged;
};

Expand Down
24 changes: 17 additions & 7 deletions src/plots/cartesian/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
return Lib.coerce(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
}

function coerce2(attr, dflt) {
return Lib.coerce2(axLayoutIn, axLayoutOut, layoutAttributes, attr, dflt);
}

function getCounterAxes(axLetter) {
return (axLetter === 'x') ? yIds : xIds;
}
Expand Down Expand Up @@ -139,13 +143,19 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {

handleAxisDefaults(axLayoutIn, axLayoutOut, coerce, defaultOptions, layoutOut);

var showSpikes = coerce('showspikes');
if(showSpikes) {
coerce('spikecolor');
coerce('spikethickness');
coerce('spikedash');
coerce('spikemode');
coerce('spikesnap');
var spikecolor = coerce2('spikecolor'),
spikethickness = coerce2('spikethickness'),
spikedash = coerce2('spikedash'),
spikemode = coerce2('spikemode'),
spikesnap = coerce2('spikesnap'),
showSpikes = coerce('showspikes', !!spikecolor || !!spikethickness || !!spikedash || !!spikemode || !!spikesnap);

if(!showSpikes) {
delete axLayoutOut.spikecolor;
delete axLayoutOut.spikethickness;
delete axLayoutOut.spikedash;
delete axLayoutOut.spikemode;
delete axLayoutOut.spikesnap;
}

var positioningOptions = {
Expand Down
4 changes: 3 additions & 1 deletion src/traces/scatter/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode) {

y0: yc - rad,
y1: yc + rad,
yLabelVal: di.y
yLabelVal: di.y,

kink: Math.max(minRad, di.mrc || 0)
});

fillHoverText(di, trace, pointData);
Expand Down
Loading
0