-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Subplot mode bars #258
Changes from 18 commits
089b335
fcdf05a
91ce34f
74e7e33
760bda3
1180a8f
9010006
11189ae
524ce13
9354fb3
48d5957
bc90474
986e8b0
fe0d8bb
0c5cf56
266caf0
790bc73
05a1b4f
4babccb
9f3d14e
da5ea21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -276,7 +276,7 @@ modeBarButtons.zoom3d = { | |
modeBarButtons.pan3d = { | ||
name: 'pan3d', | ||
title: 'Pan', | ||
attr: 'dragmode', | ||
attr: 'scene.dragmode', | ||
val: 'pan', | ||
icon: Icons.pan, | ||
click: handleDrag3d | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -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); | ||
} | ||
|
||
|
@@ -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 = { | ||
|
@@ -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 = JSON.parse(button.getAttribute('data-val')) || 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.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] = {}; | ||
|
||
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.setAttribute('data-val', JSON.stringify(currentSpikes)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we change this so that instead of using a data-attribute, we store it in an object of gd or something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. Adding a key to Where would you put this new
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what's best (or what currentSpikes exactly contains), but if there's already an existing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to keep track of the 3d axis spikes options before clearing them with
so that clicking on that modebar button again restores the initial state. |
||
} | ||
}; | ||
|
||
Plotly.relayout(gd, layoutUpdate); | ||
} | ||
|
||
modeBarButtons.zoomInGeo = { | ||
name: 'zoomInGeo', | ||
|
@@ -447,7 +447,7 @@ modeBarButtons.hoverClosestGeo = { | |
toggle: true, | ||
icon: Icons.tooltip_basic, | ||
gravity: 'ne', | ||
click: handleGeo | ||
click: toggleHover | ||
}; | ||
|
||
function handleGeo(gd, ev) { | ||
|
@@ -468,7 +468,6 @@ function handleGeo(gd, ev) { | |
geo.render(); | ||
} | ||
else if(attr === 'reset') geo.zoomReset(); | ||
else if(attr === 'hovermode') geo.showHover = !geo.showHover; | ||
} | ||
} | ||
|
||
|
@@ -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. | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will
button.getAttribute('data-val')
always be defined? If not, I think this will throw an error.Also, are we really storing JSON as a string in the dom with a data-attribute?