Skip to content

Subplot mode bars #258

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 21 commits into from
Feb 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
089b335
factor out isSelectable routine
etpinard Feb 11, 2016
fcdf05a
generalize is-active modebar update,
etpinard Feb 11, 2016
91ce34f
make dragmode and hovermode attribute of each scenes:
etpinard Feb 11, 2016
74e7e33
add fx and gl3d defaults tests
etpinard Feb 11, 2016
760bda3
don't show 3d hover labels when scene.hovermode is false
etpinard Feb 11, 2016
1180a8f
make 3d drag modebar button update scene.dragmode,
etpinard Feb 16, 2016
9010006
make camera modebar button update camera via fullLayou.scene?,
etpinard Feb 16, 2016
11189ae
make hover button extend current scene layout,
etpinard Feb 16, 2016
524ce13
use camera spec of own scene to init the camera,
etpinard Feb 16, 2016
9354fb3
rename scene.proto.handleDragmode --> scene.proto.updateFx
etpinard Feb 16, 2016
48d5957
lint
etpinard Feb 16, 2016
bc90474
add several 3d mode bar jasmine tests,
etpinard Feb 16, 2016
986e8b0
make modebar button assest abstraction more robust
etpinard Feb 16, 2016
fe0d8bb
add geo.proto.updateFx method:
etpinard Feb 16, 2016
0c5cf56
add multi-plot-type graphs mode bar button logic:
etpinard Feb 16, 2016
266caf0
generalize toggleHover mode bar button handler,
etpinard Feb 16, 2016
790bc73
add cartesian, geo and pie mode bar click handler tests
etpinard Feb 16, 2016
05a1b4f
bump down precision for circleCI
etpinard Feb 16, 2016
4babccb
make append buttons to add step more readable
etpinard Feb 17, 2016
9f3d14e
store previous scene state in button obj,
etpinard Feb 17, 2016
da5ea21
:cow2:
etpinard Feb 17, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 109 additions & 63 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ function handleCartesian(gd, ev) {
modeBarButtons.zoom3d = {
name: 'zoom3d',
title: 'Zoom',
attr: 'dragmode',
attr: 'scene.dragmode',
val: 'zoom',
icon: Icons.zoombox,
click: handleDrag3d
Expand All @@ -276,7 +276,7 @@ modeBarButtons.zoom3d = {
modeBarButtons.pan3d = {
name: 'pan3d',
title: 'Pan',
attr: 'dragmode',
attr: 'scene.dragmode',
val: 'pan',
icon: Icons.pan,
click: handleDrag3d
Expand All @@ -285,7 +285,7 @@ modeBarButtons.pan3d = {
modeBarButtons.orbitRotation = {
name: 'orbitRotation',
title: 'orbital rotation',
attr: 'dragmode',
attr: 'scene.dragmode',
val: 'orbit',
icon: Icons['3d_rotate'],
click: handleDrag3d
Expand All @@ -294,7 +294,7 @@ modeBarButtons.orbitRotation = {
modeBarButtons.tableRotation = {
name: 'tableRotation',
title: 'turntable rotation',
attr: 'dragmode',
attr: 'scene.dragmode',
val: 'turntable',
icon: Icons['z-axis'],
click: handleDrag3d
Expand All @@ -304,14 +304,16 @@ function handleDrag3d(gd, ev) {
var button = ev.currentTarget,
attr = button.getAttribute('data-attr'),
val = button.getAttribute('data-val') || true,
fullLayout = gd._fullLayout,
sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d'),
layoutUpdate = {};

layoutUpdate[attr] = val;
var parts = attr.split('.');

for(var i = 0; i < sceneIds.length; i++) {
layoutUpdate[sceneIds[i] + '.' + parts[1]] = val;
}

/*
* Dragmode will go through the relayout -> doplot -> scene.plot()
* routine where the dragmode will be set in scene.plot()
*/
Plotly.relayout(gd, layoutUpdate);
}

Expand All @@ -334,29 +336,19 @@ modeBarButtons.resetCameraLastSave3d = {
function handleCamera3d(gd, ev) {
var button = ev.currentTarget,
attr = button.getAttribute('data-attr'),
layout = gd.layout,
fullLayout = gd._fullLayout,
sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d');

for(var i = 0; i < sceneIds.length; i++) {
var sceneId = sceneIds[i],
sceneLayout = layout[sceneId],
fullSceneLayout = fullLayout[sceneId],
scene = fullSceneLayout._scene;

if(!sceneLayout || attr==='resetDefault') scene.setCameraToDefault();
if(attr === 'resetDefault') scene.setCameraToDefault();
else if(attr === 'resetLastSave') {

var cameraPos = sceneLayout.camera;
if(cameraPos) scene.setCamera(cameraPos);
else scene.setCameraToDefault();
scene.setCamera(fullSceneLayout.camera);
}
}

/*
* TODO have a sceneLastTouched in _fullLayout to only
* update the camera of the scene last touched by the user
*/
}

modeBarButtons.hoverClosest3d = {
Expand All @@ -367,50 +359,58 @@ modeBarButtons.hoverClosest3d = {
toggle: true,
icon: Icons.tooltip_basic,
gravity: 'ne',
click: function(gd, ev) {
var button = ev.currentTarget,
val = JSON.parse(button.getAttribute('data-val')) || false,
fullLayout = gd._fullLayout,
sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d');

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

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

if(val) {
layoutUpdate = val;
button.setAttribute('data-val', JSON.stringify(null));
}
else {
layoutUpdate = {'allaxes.showspikes': false};

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

// 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];
}
click: handleHover3d
};

function handleHover3d(gd, ev) {
var button = ev.currentTarget,
val = button._previousVal || false,
layout = gd.layout,
fullLayout = gd._fullLayout,
sceneIds = Plotly.Plots.getSubplotIds(fullLayout, 'gl3d');

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

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

if(val) {
layoutUpdate = Lib.extendDeep(layout, 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] = {};

sceneSpikes.hovermode = sceneLayout.hovermode;
layoutUpdate[sceneId + '.hovermode'] = 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];
}
}

button.setAttribute('data-val', JSON.stringify(currentSpikes));
}

Plotly.relayout(gd, layoutUpdate);
button._previousVal = Lib.extendDeep({}, currentSpikes);
}
};

Plotly.relayout(gd, layoutUpdate);
}

modeBarButtons.zoomInGeo = {
name: 'zoomInGeo',
Expand Down Expand Up @@ -447,7 +447,7 @@ modeBarButtons.hoverClosestGeo = {
toggle: true,
icon: Icons.tooltip_basic,
gravity: 'ne',
click: handleGeo
click: toggleHover
};

function handleGeo(gd, ev) {
Expand All @@ -468,7 +468,6 @@ function handleGeo(gd, ev) {
geo.render();
}
else if(attr === 'reset') geo.zoomReset();
else if(attr === 'hovermode') geo.showHover = !geo.showHover;
}
}

Expand All @@ -494,7 +493,54 @@ modeBarButtons.hoverClosestPie = {
};

function toggleHover(gd) {
var newHover = gd._fullLayout.hovermode ? false : 'closest';
var fullLayout = gd._fullLayout;

var onHoverVal;
if(fullLayout._hasCartesian) {
onHoverVal = fullLayout._isHoriz ? 'y' : 'x';
}
else onHoverVal = 'closest';

var newHover = gd._fullLayout.hovermode ? false : onHoverVal;

Plotly.relayout(gd, 'hovermode', newHover);
}

// buttons when more then one plot types are present

modeBarButtons.toggleHover = {
name: 'toggleHover',
title: 'Toggle show closest data on hover',
attr: 'hovermode',
val: null,
toggle: true,
icon: Icons.tooltip_basic,
gravity: 'ne',
click: function(gd, ev) {
toggleHover(gd);

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

modeBarButtons.resetViews = {
name: 'resetViews',
title: 'Reset views',
icon: Icons.home,
click: function(gd, ev) {
var button = ev.currentTarget;

button.setAttribute('data-attr', 'zoom');
button.setAttribute('data-val', 'reset');
handleCartesian(gd, ev);

button.setAttribute('data-attr', 'resetLastSave');
handleCamera3d(gd, ev);

// N.B handleCamera3d also triggers a replot for
// geo subplots.
}
};
10 changes: 7 additions & 3 deletions src/components/modebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

'use strict';

var Plotly = require('../../plotly');
var d3 = require('d3');

var Lib = require('../../lib');
var Icons = require('../../../build/ploticon');


Expand Down Expand Up @@ -204,7 +204,11 @@ proto.updateActiveButton = function(buttonClicked) {
}
}
else {
button3.classed('active', fullLayout[dataAttr]===thisval);
var val = (dataAttr === null) ?
dataAttr :
Lib.nestedProperty(fullLayout, dataAttr).get();

button3.classed('active', val === thisval);
}

});
Expand Down Expand Up @@ -260,7 +264,7 @@ proto.removeAllButtons = function() {
};

proto.destroy = function() {
Plotly.Lib.removeElement(this.container.querySelector('.modebar'));
Lib.removeElement(this.container.querySelector('.modebar'));
};

function createModeBar(gd, buttons) {
Expand Down
Loading