-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Automargin fixes #2681
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
Automargin fixes #2681
Changes from 6 commits
970db80
26278de
6dd68bd
fa86147
95f9b33
8f3da82
f9fbbc6
222f396
bd07df7
84a5695
3deab4c
bb6c720
d02c76b
5d31324
16ea22a
24aeb7c
230a782
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 |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/** | ||
* Copyright 2012-2018, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
'use strict'; | ||
|
||
var isNumeric = require('fast-isnumeric'); | ||
|
||
var aggNums = require('../../lib').aggNums; | ||
var Colorscale = require('../colorscale'); | ||
var drawColorbar = require('./draw'); | ||
|
||
/** | ||
* connectColorbar: create a colorbar from a trace, using its module to | ||
* describe the connection. | ||
* | ||
* @param {DOM element} gd | ||
* | ||
* @param {Array} cd | ||
* calcdata entry for this trace. cd[0].trace is the trace itself, and the | ||
* colorbar object will be stashed in cd[0].t.cb | ||
* | ||
* @param {object|function} moduleOpts | ||
* may be a function(gd, cd) to override the standard handling below. If | ||
* an object, should have these keys: | ||
* @param {Optional(string)} moduleOpts.container | ||
* name of the container inside the trace where the colorbar and colorscale | ||
* attributes live (ie 'marker', 'line') - omit if they're at the trace root. | ||
* @param {string} moduleOpts.min | ||
* name of the attribute holding the value of the minimum color | ||
* @param {string} moduleOpts.max | ||
* name of the attribute holding the value of the maximum color | ||
* @param {Optional(string)} moduleOpts.vals | ||
* name of the attribute holding the (numeric) color data | ||
* used only if min/max fail. May be omitted if these are always | ||
* pre-calculated. | ||
*/ | ||
module.exports = function connectColorbar(gd, cd, moduleOpts) { | ||
if(typeof moduleOpts === 'function') return moduleOpts(gd, cd); | ||
|
||
var trace = cd[0].trace; | ||
var cbId = 'cb' + trace.uid; | ||
var containerName = moduleOpts.container; | ||
var container = containerName ? trace[containerName] : trace; | ||
|
||
gd._fullLayout._infolayer.selectAll('.' + cbId).remove(); | ||
if(!container || !container.showscale) return; | ||
|
||
var zmin = container[moduleOpts.min]; | ||
var zmax = container[moduleOpts.max]; | ||
|
||
var valAttr = moduleOpts.vals; | ||
var vals; | ||
if(Array.isArray(valAttr)) { | ||
for(var i = 0; i < valAttr.length; i++) { | ||
vals = container[valAttr[i]]; | ||
if(vals) break; | ||
} | ||
} | ||
else vals = container[valAttr]; | ||
|
||
if(vals) { | ||
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. (Non-blocking) I'm curious to see what would happen (i.e. which tests would fail if any) if we drop the logic around vals here. cmin/cmax or zmin/zmax should always be computed during the calc step which should happen before this block. 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. yeah, looks like calculating the range while drawing the colorbar is obsolete, good call! Though I can't seem to run the image tests all the way through locally anymore, so we'll see in a few minutes -> f9fbbc6 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. |
||
if(!isNumeric(zmin)) zmin = aggNums(Math.min, null, vals); | ||
if(!isNumeric(zmax)) zmax = aggNums(Math.max, null, vals); | ||
} | ||
|
||
var cb = cd[0].t.cb = drawColorbar(gd, cbId); | ||
var sclFunc = Colorscale.makeColorScaleFunc( | ||
Colorscale.extractScale( | ||
container.colorscale, | ||
zmin, | ||
zmax | ||
), | ||
{ noNumericCheck: true } | ||
); | ||
|
||
cb.fillcolor(sclFunc) | ||
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254}) | ||
.options(container.colorbar)(); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,15 +61,9 @@ module.exports = function(gd) { | |
|
||
// remove exiting sliders and their corresponding clip paths | ||
rangeSliders.exit().each(function(axisOpts) { | ||
var rangeSlider = d3.select(this), | ||
opts = axisOpts[constants.name]; | ||
|
||
rangeSlider.remove(); | ||
var opts = axisOpts[constants.name]; | ||
fullLayout._topdefs.select('#' + opts._clipId).remove(); | ||
}); | ||
|
||
// remove push margin object(s) | ||
if(rangeSliders.exit().size()) clearPushMargins(gd); | ||
}).remove(); | ||
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. Ha |
||
|
||
// return early if no range slider is visible | ||
if(rangeSliderData.length === 0) return; | ||
|
@@ -602,16 +596,3 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { | |
}); | ||
grabAreaMax.attr('height', opts._height); | ||
} | ||
|
||
function clearPushMargins(gd) { | ||
var pushMargins = gd._fullLayout._pushmargin || {}, | ||
keys = Object.keys(pushMargins); | ||
|
||
for(var i = 0; i < keys.length; i++) { | ||
var k = keys[i]; | ||
|
||
if(k.indexOf(constants.name) !== -1) { | ||
Plots.autoMargin(gd, k); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,10 @@ module.exports = function draw(gd) { | |
* ... | ||
*/ | ||
|
||
function clearAutoMargin(menuOpts) { | ||
Plots.autoMargin(gd, autoMarginId(menuOpts)); | ||
} | ||
|
||
// draw update menu container | ||
var menus = fullLayout._menulayer | ||
.selectAll('g.' + constants.containerClassName) | ||
|
@@ -63,10 +67,15 @@ module.exports = function draw(gd) { | |
.classed(constants.containerClassName, true) | ||
.style('cursor', 'pointer'); | ||
|
||
menus.exit().remove(); | ||
|
||
// remove push margin object(s) | ||
if(menus.exit().size()) clearPushMargins(gd); | ||
menus.exit().each(function() { | ||
// Most components don't need to explicitly remove autoMargin, because | ||
// marginPushers does this - but updatemenu updates don't go through | ||
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. Why is this the case? Is it because updatemenus attributes are under the 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. Oh man, I missed sliders in this PR but sure enough, they still have the older pattern - thanks, I'll take a look at those. 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. Updated sliders in 3deab4c |
||
// a full replot so we need to explicitly remove it. | ||
// This is for removing *all* updatemenus, removing individuals is | ||
// handled below, in hederGroups.exit | ||
d3.select(this).selectAll('g.' + constants.headerGroupClassName) | ||
.each(clearAutoMargin); | ||
}).remove(); | ||
|
||
// return early if no update menus are visible | ||
if(menuData.length === 0) return; | ||
|
@@ -97,21 +106,13 @@ module.exports = function draw(gd) { | |
if(headerGroups.enter().size()) { | ||
// make sure gButton is on top of all headers | ||
gButton.node().parentNode.appendChild(gButton.node()); | ||
|
||
gButton | ||
.call(removeAllButtons) | ||
.attr(constants.menuIndexAttrName, '-1'); | ||
gButton.call(removeAllButtons); | ||
} | ||
|
||
headerGroups.exit().each(function(menuOpts) { | ||
d3.select(this).remove(); | ||
|
||
gButton | ||
.call(removeAllButtons) | ||
.attr(constants.menuIndexAttrName, '-1'); | ||
|
||
Plots.autoMargin(gd, constants.autoMarginIdRoot + menuOpts._index); | ||
}); | ||
gButton.call(removeAllButtons); | ||
clearAutoMargin(menuOpts); | ||
}).remove(); | ||
|
||
// draw headers! | ||
headerGroups.each(function(menuOpts) { | ||
|
@@ -219,16 +220,8 @@ function drawHeader(gd, gHeader, gButton, scrollBox, menuOpts) { | |
}); | ||
|
||
header.on('click', function() { | ||
gButton.call(removeAllButtons); | ||
|
||
|
||
// if this menu is active, fold the dropdown container | ||
// otherwise, make this menu active | ||
gButton.attr( | ||
constants.menuIndexAttrName, | ||
isActive(gButton, menuOpts) ? | ||
-1 : | ||
String(menuOpts._index) | ||
gButton.call(removeAllButtons, | ||
String(isActive(gButton, menuOpts) ? -1 : menuOpts._index) | ||
); | ||
|
||
drawButtons(gd, gHeader, gButton, scrollBox, menuOpts); | ||
|
@@ -608,7 +601,7 @@ function findDimensions(gd, menuOpts) { | |
dims.lx = Math.round(dims.lx); | ||
dims.ly = Math.round(dims.ly); | ||
|
||
Plots.autoMargin(gd, constants.autoMarginIdRoot + menuOpts._index, { | ||
Plots.autoMargin(gd, autoMarginId(menuOpts), { | ||
x: menuOpts.x, | ||
y: menuOpts.y, | ||
l: paddedWidth * ({right: 1, center: 0.5}[xanchor] || 0), | ||
|
@@ -618,6 +611,10 @@ function findDimensions(gd, menuOpts) { | |
}); | ||
} | ||
|
||
function autoMarginId(menuOpts) { | ||
return constants.autoMarginIdRoot + menuOpts._index; | ||
} | ||
|
||
// set item positions (mutates posOpts) | ||
function setItemPosition(item, menuOpts, posOpts, overrideOpts) { | ||
overrideOpts = overrideOpts || {}; | ||
|
@@ -655,19 +652,8 @@ function setItemPosition(item, menuOpts, posOpts, overrideOpts) { | |
posOpts.index++; | ||
} | ||
|
||
function removeAllButtons(gButton) { | ||
gButton.selectAll('g.' + constants.dropdownButtonClassName).remove(); | ||
} | ||
|
||
function clearPushMargins(gd) { | ||
var pushMargins = gd._fullLayout._pushmargin || {}; | ||
var keys = Object.keys(pushMargins); | ||
|
||
for(var i = 0; i < keys.length; i++) { | ||
var k = keys[i]; | ||
|
||
if(k.indexOf(constants.autoMarginIdRoot) !== -1) { | ||
Plots.autoMargin(gd, k); | ||
} | ||
} | ||
function removeAllButtons(gButton, newMenuIndexAttr) { | ||
gButton | ||
.attr(constants.menuIndexAttrName, newMenuIndexAttr || '-1') | ||
.selectAll('g.' + constants.dropdownButtonClassName).remove(); | ||
} |
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.
So, contour still gets its own version on
module._colorbar
inhttps://github.com/plotly/plotly.js/blob/fa8614750586a2901ccf65a520521bb570eb7026/src/traces/contour/colorbar.js
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.
... and that's the only exception?
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.
Yes, contour and those that inherit from it (
contourcarpet
,contourgl
,histogram2dcontour
).I should note that there's one other place
module.colorbar
gets used, that's incolorbar.draw
for getting thenestedProperty
string for title editing. If contour colorbars weren't at the module root we'd need to set acontainer
property of the function which would be a bit hacky... alternatively we could either a) make this function bemodule.colorbar.func
, or b) incorporate contour into this routine directly, triggered by some other property ofmodule.colorbar
.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.
This sounds cleaner to me. But no need to do this in this PR.