Skip to content

Commit fa86147

Browse files
committed
refactor colorbars for simpler connection to trace attributes
Also fixes and tests a few traces that should have supported colorbars but didn't and some cases of editing colorbars that didn't previously work
1 parent 6dd68bd commit fa86147

File tree

36 files changed

+428
-331
lines changed

36 files changed

+428
-331
lines changed

src/components/colorbar/connect.js

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var isNumeric = require('fast-isnumeric');
13+
14+
var aggNums = require('../../lib').aggNums;
15+
var Colorscale = require('../colorscale');
16+
var drawColorbar = require('./draw');
17+
18+
/**
19+
* connectColorbar: create a colorbar from a trace, using its module to
20+
* describe the connection.
21+
*
22+
* @param {DOM element} gd
23+
*
24+
* @param {Array} cd
25+
* calcdata entry for this trace. cd[0].trace is the trace itself, and the
26+
* colorbar object will be stashed in cd[0].t.cb
27+
*
28+
* @param {object|function} moduleOpts
29+
* may be a function(gd, cd) to override the standard handling below. If
30+
* an object, should have these keys:
31+
* @param {Optional(string)} moduleOpts.container
32+
* name of the container inside the trace where the colorbar and colorscale
33+
* attributes live (ie 'marker', 'line') - omit if they're at the trace root.
34+
* @param {string} moduleOpts.min
35+
* name of the attribute holding the value of the minimum color
36+
* @param {string} moduleOpts.max
37+
* name of the attribute holding the value of the maximum color
38+
* @param {Optional(string)} moduleOpts.vals
39+
* name of the attribute holding the (numeric) color data
40+
* used only if min/max fail. May be omitted if these are always
41+
* pre-calculated.
42+
*/
43+
module.exports = function connectColorbar(gd, cd, moduleOpts) {
44+
if(typeof moduleOpts === 'function') return moduleOpts(gd, cd);
45+
46+
var trace = cd[0].trace;
47+
var cbId = 'cb' + trace.uid;
48+
var containerName = moduleOpts.container;
49+
var container = containerName ? trace[containerName] : trace;
50+
51+
gd._fullLayout._infolayer.selectAll('.' + cbId).remove();
52+
if(!container || !container.showscale) return;
53+
54+
var zmin = container[moduleOpts.min];
55+
var zmax = container[moduleOpts.max];
56+
57+
var valAttr = moduleOpts.vals;
58+
var vals;
59+
if(Array.isArray(valAttr)) {
60+
for(var i = 0; i < valAttr.length; i++) {
61+
vals = container[valAttr[i]];
62+
if(vals) break;
63+
}
64+
}
65+
else vals = container[valAttr];
66+
67+
if(vals) {
68+
if(!isNumeric(zmin)) zmin = aggNums(Math.min, null, vals);
69+
if(!isNumeric(zmax)) zmax = aggNums(Math.max, null, vals);
70+
}
71+
72+
var cb = cd[0].t.cb = drawColorbar(gd, cbId);
73+
var sclFunc = Colorscale.makeColorScaleFunc(
74+
Colorscale.extractScale(
75+
container.colorscale,
76+
zmin,
77+
zmax
78+
),
79+
{ noNumericCheck: true }
80+
);
81+
82+
cb.fillcolor(sclFunc)
83+
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254})
84+
.options(container.colorbar)();
85+
};

src/components/colorbar/draw.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -447,12 +447,10 @@ module.exports = function draw(gd, id) {
447447
}
448448

449449
function drawTitle(titleClass, titleOpts) {
450-
var trace = getTrace(),
451-
propName;
452-
if(Registry.traceIs(trace, 'markerColorscale')) {
453-
propName = 'marker.colorbar.title';
454-
}
455-
else propName = 'colorbar.title';
450+
var trace = getTrace();
451+
var propName = 'colorbar.title';
452+
var containerName = trace._module.colorbar.container;
453+
if(containerName) propName = containerName + '.' + propName;
456454

457455
var dfltTitleOpts = {
458456
propContainer: cbAxisOut,

src/components/colorbar/index.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212

1313
exports.attributes = require('./attributes');
14-
1514
exports.supplyDefaults = require('./defaults');
16-
15+
exports.connect = require('./connect');
1716
exports.draw = require('./draw');
18-
1917
exports.hasColorbar = require('./has_colorbar');

src/plot_api/helpers.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,14 @@ exports.cleanData = function(data) {
274274
}
275275

276276
// fix typo in colorscale definition
277-
if(Registry.traceIs(trace, '2dMap')) {
278-
if(trace.colorscale === 'YIGnBu') trace.colorscale = 'YlGnBu';
279-
if(trace.colorscale === 'YIOrRd') trace.colorscale = 'YlOrRd';
280-
}
281-
if(Registry.traceIs(trace, 'markerColorscale') && trace.marker) {
282-
var cont = trace.marker;
283-
if(cont.colorscale === 'YIGnBu') cont.colorscale = 'YlGnBu';
284-
if(cont.colorscale === 'YIOrRd') cont.colorscale = 'YlOrRd';
277+
var _module = Registry.getModule(trace);
278+
if(_module && _module.colorbar) {
279+
var containerName = _module.colorbar.container;
280+
var container = containerName ? trace[containerName] : trace;
281+
if(container && container.colorscale) {
282+
if(container.colorscale === 'YIGnBu') container.colorscale = 'YlGnBu';
283+
if(container.colorscale === 'YIOrRd') container.colorscale = 'YlOrRd';
284+
}
285285
}
286286

287287
// fix typo in surface 'highlight*' definitions

src/plot_api/plot_api.js

+31-25
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ var Polar = require('../plots/polar/legacy');
2626
var Axes = require('../plots/cartesian/axes');
2727
var Drawing = require('../components/drawing');
2828
var Color = require('../components/color');
29+
var connectColorbar = require('../components/colorbar/connect');
2930
var initInteractions = require('../plots/cartesian/graph_interact').initInteractions;
3031
var xmlnsNamespaces = require('../constants/xmlns_namespaces');
3132
var svgTextUtils = require('../lib/svg_text_utils');
@@ -265,10 +266,11 @@ exports.plot = function(gd, data, layout, config) {
265266
for(i = 0; i < calcdata.length; i++) {
266267
cd = calcdata[i];
267268
trace = cd[0].trace;
268-
if(trace.visible !== true || !trace._module.colorbar) {
269+
var colorbarOpts = trace._module.colorbar;
270+
if(trace.visible !== true || !colorbarOpts) {
269271
Plots.autoMargin(gd, 'cb' + trace.uid);
270272
}
271-
else trace._module.colorbar(gd, cd);
273+
else connectColorbar(gd, cd, colorbarOpts);
272274
}
273275

274276
Plots.doAutoMargin(gd);
@@ -1448,6 +1450,11 @@ function _restyle(gd, aobj, traces) {
14481450

14491451
if(newVal === undefined) continue;
14501452

1453+
var finalPart = param.parts[param.parts.length - 1];
1454+
var prefix = ai.substr(0, ai.length - finalPart.length - 1);
1455+
var prefixDot = prefix ? prefix + '.' : '';
1456+
var innerContFull = prefix ? Lib.nestedProperty(contFull, prefix) : contFull;
1457+
14511458
valObject = PlotSchema.getTraceValObject(contFull, param.parts);
14521459

14531460
if(valObject && valObject.impliedEdits && newVal !== null) {
@@ -1461,31 +1468,30 @@ function _restyle(gd, aobj, traces) {
14611468
// note that colorbar fractional sizing is based on the
14621469
// original plot size, before anything (like a colorbar)
14631470
// increases the margins
1464-
else if(ai === 'colorbar.thicknessmode' && param.get() !== newVal &&
1465-
['fraction', 'pixels'].indexOf(newVal) !== -1 &&
1466-
contFull.colorbar) {
1467-
var thicknorm =
1468-
['top', 'bottom'].indexOf(contFull.colorbar.orient) !== -1 ?
1469-
(fullLayout.height - fullLayout.margin.t - fullLayout.margin.b) :
1470-
(fullLayout.width - fullLayout.margin.l - fullLayout.margin.r);
1471-
doextra('colorbar.thickness', contFull.colorbar.thickness *
1472-
(newVal === 'fraction' ? 1 / thicknorm : thicknorm), i);
1473-
}
1474-
else if(ai === 'colorbar.lenmode' && param.get() !== newVal &&
1475-
['fraction', 'pixels'].indexOf(newVal) !== -1 &&
1476-
contFull.colorbar) {
1477-
var lennorm =
1478-
['top', 'bottom'].indexOf(contFull.colorbar.orient) !== -1 ?
1479-
(fullLayout.width - fullLayout.margin.l - fullLayout.margin.r) :
1480-
(fullLayout.height - fullLayout.margin.t - fullLayout.margin.b);
1481-
doextra('colorbar.len', contFull.colorbar.len *
1482-
(newVal === 'fraction' ? 1 / lennorm : lennorm), i);
1483-
}
1484-
else if(ai === 'colorbar.tick0' || ai === 'colorbar.dtick') {
1485-
doextra('colorbar.tickmode', 'linear', i);
1471+
else if((finalPart === 'thicknessmode' || finalPart === 'lenmode') &&
1472+
oldVal !== newVal &&
1473+
(newVal === 'fraction' || newVal === 'pixels') &&
1474+
innerContFull
1475+
) {
1476+
if(finalPart === 'thicknessmode') {
1477+
var thicknorm =
1478+
['top', 'bottom'].indexOf(innerContFull.orient) !== -1 ?
1479+
(fullLayout.height - fullLayout.margin.t - fullLayout.margin.b) :
1480+
(fullLayout.width - fullLayout.margin.l - fullLayout.margin.r);
1481+
doextra(prefixDot + 'thickness', innerContFull.thickness *
1482+
(newVal === 'fraction' ? 1 / thicknorm : thicknorm), i);
1483+
}
1484+
else {
1485+
var lennorm =
1486+
['top', 'bottom'].indexOf(innerContFull.orient) !== -1 ?
1487+
(fullLayout.width - fullLayout.margin.l - fullLayout.margin.r) :
1488+
(fullLayout.height - fullLayout.margin.t - fullLayout.margin.b);
1489+
doextra(prefixDot + 'len', innerContFull.len *
1490+
(newVal === 'fraction' ? 1 / lennorm : lennorm), i);
1491+
}
14861492
}
14871493

1488-
if(ai === 'type' && (newVal === 'pie') !== (oldVal === 'pie')) {
1494+
else if(ai === 'type' && (newVal === 'pie') !== (oldVal === 'pie')) {
14891495
var labelsTo = 'x',
14901496
valuesTo = 'y';
14911497
if((newVal === 'bar' || oldVal === 'bar') && cont.orientation === 'h') {

src/plot_api/subroutines.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,10 @@ exports.doColorBars = function(gd) {
473473
cb._opts.line.color : trace.line.color
474474
});
475475
}
476-
if(Registry.traceIs(trace, 'markerColorscale')) {
477-
cb.options(trace.marker.colorbar)();
478-
}
479-
else cb.options(trace.colorbar)();
476+
var moduleOpts = trace._module.colorbar;
477+
var containerName = moduleOpts.container;
478+
var opts = (containerName ? trace[containerName] : trace).colorbar;
479+
cb.options(opts)();
480480
}
481481
}
482482

src/traces/bar/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Bar.supplyDefaults = require('./defaults');
1717
Bar.supplyLayoutDefaults = require('./layout_defaults');
1818
Bar.calc = require('./calc');
1919
Bar.setPositions = require('./set_positions');
20-
Bar.colorbar = require('../scatter/colorbar');
20+
Bar.colorbar = require('../scatter/marker_colorbar');
2121
Bar.arraysToCalcdata = require('./arrays_to_calcdata');
2222
Bar.plot = require('./plot');
2323
Bar.style = require('./style').style;
@@ -28,7 +28,7 @@ Bar.selectPoints = require('./select');
2828
Bar.moduleType = 'trace';
2929
Bar.name = 'bar';
3030
Bar.basePlotModule = require('../../plots/cartesian');
31-
Bar.categories = ['cartesian', 'svg', 'bar', 'oriented', 'markerColorscale', 'errorBarsOK', 'showLegend', 'zoomScale'];
31+
Bar.categories = ['cartesian', 'svg', 'bar', 'oriented', 'errorBarsOK', 'showLegend', 'zoomScale'];
3232
Bar.meta = {
3333
description: [
3434
'The data visualized by the span of the bars is set in `y`',

src/traces/cone/colorbar.js

-33
This file was deleted.

src/traces/cone/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ module.exports = {
1616

1717
attributes: require('./attributes'),
1818
supplyDefaults: require('./defaults'),
19-
colorbar: require('./colorbar'),
19+
colorbar: {
20+
min: 'cmin',
21+
max: 'cmax'
22+
// no vals, these are calculated automatically from vector norms
23+
},
2024
calc: require('./calc'),
2125
plot: require('./convert'),
2226

src/traces/heatmap/colorbar.js

+4-34
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,10 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

12-
var isNumeric = require('fast-isnumeric');
13-
14-
var Lib = require('../../lib');
15-
var Colorscale = require('../../components/colorscale');
16-
var drawColorbar = require('../../components/colorbar/draw');
17-
18-
19-
module.exports = function colorbar(gd, cd) {
20-
var trace = cd[0].trace,
21-
cbId = 'cb' + trace.uid,
22-
zmin = trace.zmin,
23-
zmax = trace.zmax;
24-
25-
if(!isNumeric(zmin)) zmin = Lib.aggNums(Math.min, null, trace.z);
26-
if(!isNumeric(zmax)) zmax = Lib.aggNums(Math.max, null, trace.z);
27-
28-
gd._fullLayout._infolayer.selectAll('.' + cbId).remove();
29-
30-
if(!trace.showscale) return;
31-
32-
var cb = cd[0].t.cb = drawColorbar(gd, cbId);
33-
var sclFunc = Colorscale.makeColorScaleFunc(
34-
Colorscale.extractScale(
35-
trace.colorscale,
36-
zmin,
37-
zmax
38-
),
39-
{ noNumericCheck: true }
40-
);
41-
42-
cb.fillcolor(sclFunc)
43-
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254})
44-
.options(trace.colorbar)();
11+
module.exports = {
12+
min: 'zmin',
13+
max: 'zmax',
14+
vals: 'z'
4515
};

src/traces/histogram/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Histogram.plot = require('../bar/plot');
3535
Histogram.layerName = 'barlayer';
3636
Histogram.style = require('../bar/style').style;
3737
Histogram.styleOnSelect = require('../bar/style').styleOnSelect;
38-
Histogram.colorbar = require('../scatter/colorbar');
38+
Histogram.colorbar = require('../scatter/marker_colorbar');
3939
Histogram.hoverPoints = require('./hover');
4040
Histogram.selectPoints = require('../bar/select');
4141
Histogram.eventData = require('./event_data');

0 commit comments

Comments
 (0)