Skip to content

Commit

Permalink
Merge pull request #3236 from plotly/ui-key
Browse files Browse the repository at this point in the history
Preserve ui state across Plotly.react redraws
  • Loading branch information
alexcjohnson committed Nov 30, 2018
2 parents db66ff1 + 067bd7d commit 7bb5daa
Show file tree
Hide file tree
Showing 50 changed files with 2,768 additions and 1,124 deletions.
6 changes: 3 additions & 3 deletions src/components/annotations/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
});
},
doneFn: function() {
Registry.call('relayout', gd, getUpdateObj());
Registry.call('_guiRelayout', gd, getUpdateObj());
var notesBox = document.querySelector('.js-notes-box-panel');
if(notesBox) notesBox.redraw(notesBox.selectedObj);
}
Expand Down Expand Up @@ -667,7 +667,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
},
doneFn: function() {
setCursor(annTextGroupInner);
Registry.call('relayout', gd, getUpdateObj());
Registry.call('_guiRelayout', gd, getUpdateObj());
var notesBox = document.querySelector('.js-notes-box-panel');
if(notesBox) notesBox.redraw(notesBox.selectedObj);
}
Expand All @@ -691,7 +691,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
modifyBase(ya._name + '.autorange', true);
}

Registry.call('relayout', gd, getUpdateObj());
Registry.call('_guiRelayout', gd, getUpdateObj());
});
}
else annText.call(textLayout);
Expand Down
26 changes: 14 additions & 12 deletions src/components/colorbar/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,15 +485,10 @@ module.exports = function draw(gd, id) {
}

function drawTitle(titleClass, titleOpts) {
var trace = getTrace();
var propName = 'colorbar.title';
var containerName = trace._module.colorbar.container;
if(containerName) propName = containerName + '.' + propName;

var dfltTitleOpts = {
propContainer: cbAxisOut,
propName: propName,
traceIndex: trace.index,
propName: getPropName('title'),
traceIndex: getTrace().index,
placeholder: fullLayout._dfltTitle.colorbar,
containerGroup: container.select('.cbtitle')
};
Expand Down Expand Up @@ -645,11 +640,10 @@ module.exports = function draw(gd, id) {
setCursor(container);

if(xf !== undefined && yf !== undefined) {
Registry.call('restyle',
gd,
{'colorbar.x': xf, 'colorbar.y': yf},
getTrace().index
);
var update = {};
update[getPropName('x')] = xf;
update[getPropName('y')] = yf;
Registry.call('_guiRestyle', gd, update, getTrace().index);
}
}
});
Expand All @@ -667,6 +661,14 @@ module.exports = function draw(gd, id) {
}
}

function getPropName(suffix) {
var trace = getTrace();
var propName = 'colorbar.';
var containerName = trace._module.colorbar.container;
if(containerName) propName = containerName + '.' + propName;
return propName + suffix;
}

// setter/getters for every item defined in opts
Object.keys(opts).forEach(function(name) {
component[name] = function(v) {
Expand Down
13 changes: 11 additions & 2 deletions src/components/legend/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,15 @@ module.exports = {
'or *bottom* of the legend.'
].join(' ')
},
editType: 'legend',
uirevision: {
valType: 'any',
role: 'info',
editType: 'none',
description: [
'Controls persistence of legend-driven changes in trace and pie label',
'visibility. Defaults to `layout.uirevision`.'
].join(' ')
},
valign: {
valType: 'enumerated',
values: ['top', 'middle', 'bottom'],
Expand All @@ -130,5 +138,6 @@ module.exports = {
description: [
'Sets the vertical alignment of the symbols with respect to their associated text.',
].join(' ')
}
},
editType: 'legend'
};
6 changes: 5 additions & 1 deletion src/components/legend/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,18 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
basePlotLayoutAttributes, 'showlegend',
legendReallyHasATrace && legendTraceCount > 1);

if(showLegend === false) return;
if(showLegend === false && !containerIn.uirevision) return;

var containerOut = Template.newContainer(layoutOut, 'legend');

function coerce(attr, dflt) {
return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
}

coerce('uirevision', layoutOut.uirevision);

if(showLegend === false) return;

coerce('bgcolor', layoutOut.paper_bgcolor);
coerce('bordercolor');
coerce('borderwidth');
Expand Down
4 changes: 2 additions & 2 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ module.exports = function draw(gd) {
},
doneFn: function() {
if(xf !== undefined && yf !== undefined) {
Registry.call('relayout', gd, {'legend.x': xf, 'legend.y': yf});
Registry.call('_guiRelayout', gd, {'legend.x': xf, 'legend.y': yf});
}
},
clickFn: function(numClicks, e) {
Expand Down Expand Up @@ -445,7 +445,7 @@ function drawTexts(g, gd, maxLength) {
update.name = newName;
}

return Registry.call('restyle', gd, update, traceIndex);
return Registry.call('_guiRestyle', gd, update, traceIndex);
});
} else {
textLayout(textEl);
Expand Down
4 changes: 2 additions & 2 deletions src/components/legend/handle_click.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ module.exports = function handleClick(g, gd, numClicks) {
}
}

Registry.call('relayout', gd, 'hiddenlabels', hiddenSlices);
Registry.call('_guiRelayout', gd, 'hiddenlabels', hiddenSlices);
} else {
var hasLegendgroup = legendgroup && legendgroup.length;
var traceIndicesInGroup = [];
Expand Down Expand Up @@ -217,6 +217,6 @@ module.exports = function handleClick(g, gd, numClicks) {
}
}

Registry.call('restyle', gd, attrUpdate, attrIndices);
Registry.call('_guiRestyle', gd, attrUpdate, attrIndices);
}
};
76 changes: 35 additions & 41 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ function handleCartesian(gd, ev) {
aobj[astr] = val;
}

Registry.call('relayout', gd, aobj);
Registry.call('_guiRelayout', gd, aobj);
}

modeBarButtons.zoom3d = {
Expand Down Expand Up @@ -317,7 +317,7 @@ function handleDrag3d(gd, ev) {
var val2d = (val === 'pan') ? val : 'zoom';
layoutUpdate.dragmode = val2d;

Registry.call('relayout', gd, layoutUpdate);
Registry.call('_guiRelayout', gd, layoutUpdate);
}

modeBarButtons.resetCameraDefault3d = {
Expand Down Expand Up @@ -356,7 +356,7 @@ function handleCamera3d(gd, ev) {
}
}

Registry.call('relayout', gd, aobj);
Registry.call('_guiRelayout', gd, aobj);
}

modeBarButtons.hoverClosest3d = {
Expand All @@ -370,54 +370,48 @@ modeBarButtons.hoverClosest3d = {
click: handleHover3d
};

function handleHover3d(gd, ev) {
function getNextHover3d(gd, ev) {
var button = ev.currentTarget;
var val = button._previousVal || false;
var layout = gd.layout;
var val = button._previousVal;
var fullLayout = gd._fullLayout;
var sceneIds = fullLayout._subplots.gl3d;

var axes = ['xaxis', 'yaxis', 'zaxis'];
var spikeAttrs = ['showspikes', 'spikesides', 'spikethickness', 'spikecolor'];

// initialize 'current spike' object to be stored in the DOM
var currentSpikes = {};
var axisSpikes = {};
var layoutUpdate = {};

if(val) {
layoutUpdate = Lib.extendDeep(layout, val);
layoutUpdate = val;
button._previousVal = null;
}
else {
layoutUpdate = {
'allaxes.showspikes': false
};

for(var i = 0; i < sceneIds.length; i++) {
var sceneId = sceneIds[i],
sceneLayout = fullLayout[sceneId],
sceneSpikes = currentSpikes[sceneId] = {};
var sceneId = sceneIds[i];
var sceneLayout = fullLayout[sceneId];

sceneSpikes.hovermode = sceneLayout.hovermode;
layoutUpdate[sceneId + '.hovermode'] = false;
var hovermodeAStr = sceneId + '.hovermode';
currentSpikes[hovermodeAStr] = sceneLayout.hovermode;
layoutUpdate[hovermodeAStr] = false;

// copy all the current spike attrs
for(var j = 0; j < 3; j++) {
var axis = axes[j];
axisSpikes = sceneSpikes[axis] = {};

for(var k = 0; k < spikeAttrs.length; k++) {
var spikeAttr = spikeAttrs[k];
axisSpikes[spikeAttr] = sceneLayout[axis][spikeAttr];
}
var spikeAStr = sceneId + '.' + axis + '.showspikes';
layoutUpdate[spikeAStr] = false;
currentSpikes[spikeAStr] = sceneLayout[axis].showspikes;
}
}

button._previousVal = Lib.extendDeep({}, currentSpikes);
button._previousVal = currentSpikes;
}
return layoutUpdate;
}

Registry.call('relayout', gd, layoutUpdate);
function handleHover3d(gd, ev) {
var layoutUpdate = getNextHover3d(gd, ev);
Registry.call('_guiRelayout', gd, layoutUpdate);
}

modeBarButtons.zoomInGeo = {
Expand Down Expand Up @@ -473,7 +467,7 @@ function handleGeo(gd, ev) {
var scale = geoLayout.projection.scale;
var newScale = (val === 'in') ? 2 * scale : 0.5 * scale;

Registry.call('relayout', gd, id + '.projection.scale', newScale);
Registry.call('_guiRelayout', gd, id + '.projection.scale', newScale);
} else if(attr === 'reset') {
resetView(gd, 'geo');
}
Expand Down Expand Up @@ -501,18 +495,20 @@ modeBarButtons.hoverClosestPie = {
click: toggleHover
};

function toggleHover(gd) {
function getNextHover(gd) {
var fullLayout = gd._fullLayout;

var onHoverVal;
if(fullLayout.hovermode) return false;

if(fullLayout._has('cartesian')) {
onHoverVal = fullLayout._isHoriz ? 'y' : 'x';
return fullLayout._isHoriz ? 'y' : 'x';
}
else onHoverVal = 'closest';

var newHover = gd._fullLayout.hovermode ? false : onHoverVal;
return 'closest';
}

Registry.call('relayout', gd, 'hovermode', newHover);
function toggleHover(gd) {
var newHover = getNextHover(gd);
Registry.call('_guiRelayout', gd, 'hovermode', newHover);
}

// buttons when more then one plot types are present
Expand All @@ -526,12 +522,10 @@ modeBarButtons.toggleHover = {
icon: Icons.tooltip_basic,
gravity: 'ne',
click: function(gd, ev) {
toggleHover(gd);
var layoutUpdate = getNextHover3d(gd, ev);
layoutUpdate.hovermode = getNextHover(gd);

// the 3d hovermode update must come
// last so that layout.hovermode update does not
// override scene?.hovermode?.layout.
handleHover3d(gd, ev);
Registry.call('_guiRelayout', gd, layoutUpdate);
}
};

Expand Down Expand Up @@ -567,7 +561,7 @@ modeBarButtons.toggleSpikelines = {

var aobj = setSpikelineVisibility(gd);

Registry.call('relayout', gd, aobj);
Registry.call('_guiRelayout', gd, aobj);
}
};

Expand Down Expand Up @@ -614,5 +608,5 @@ function resetView(gd, subplotType) {
}
}

Registry.call('relayout', gd, aObj);
Registry.call('_guiRelayout', gd, aObj);
}
2 changes: 1 addition & 1 deletion src/components/rangeselector/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ module.exports = function draw(gd) {
button.on('click', function() {
if(gd._dragged) return;

Registry.call('relayout', gd, update);
Registry.call('_guiRelayout', gd, update);
});

button.on('mouseover', function() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/rangeslider/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ function setDataRange(rangeSlider, gd, axisOpts, opts) {
dataMax = clamp(opts.p2d(opts._pixelMax));

window.requestAnimationFrame(function() {
Registry.call('relayout', gd, axisOpts._name + '.range', [dataMin, dataMax]);
Registry.call('_guiRelayout', gd, axisOpts._name + '.range', [dataMin, dataMax]);
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/shapes/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer) {

// Don't rely on clipPath being activated during re-layout
setClipPath(shapePath, gd, shapeOptions);
Registry.call('relayout', gd, editHelpers.getUpdateObj());
Registry.call('_guiRelayout', gd, editHelpers.getUpdateObj());
}

function abortDrag() {
Expand Down
4 changes: 2 additions & 2 deletions src/components/titles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,9 @@ function draw(gd, titleClass, options) {
el.call(svgTextUtils.makeEditable, {gd: gd})
.on('edit', function(text) {
if(traceIndex !== undefined) {
Registry.call('restyle', gd, prop, text, traceIndex);
Registry.call('_guiRestyle', gd, prop, text, traceIndex);
} else {
Registry.call('relayout', gd, prop, text);
Registry.call('_guiRelayout', gd, prop, text);
}
})
.on('cancel', function() {
Expand Down
3 changes: 2 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ var plotApi = require('./plot_api');
var methodNames = Object.keys(plotApi);
for(var i = 0; i < methodNames.length; i++) {
var name = methodNames[i];
exports[name] = plotApi[name];
// _ -> private API methods, but still registered for internal use
if(name.charAt(0) !== '_') exports[name] = plotApi[name];
register({
moduleType: 'apiMethod',
name: name,
Expand Down
4 changes: 4 additions & 0 deletions src/plot_api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ exports.restyle = main.restyle;
exports.relayout = main.relayout;
exports.redraw = main.redraw;
exports.update = main.update;
exports._guiRestyle = main._guiRestyle;
exports._guiRelayout = main._guiRelayout;
exports._guiUpdate = main._guiUpdate;
exports._storeDirectGUIEdit = main._storeDirectGUIEdit;
exports.react = main.react;
exports.extendTraces = main.extendTraces;
exports.prependTraces = main.prependTraces;
Expand Down
Loading

0 comments on commit 7bb5daa

Please sign in to comment.