Skip to content
This repository was archived by the owner on Apr 21, 2023. It is now read-only.

Commit b66562f

Browse files
mboorstinquickgiant
authored andcommitted
Dynamic behavior draft
(cherry picked from commit ebf6e9f)
1 parent 0e530a3 commit b66562f

File tree

4 files changed

+61
-11
lines changed

4 files changed

+61
-11
lines changed

src/plot_api/plot_api.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ var numericNameWarningCountLimit = 5;
5454
* all the stuff that doesn't pertain to any individual trace
5555
* @param {object} config
5656
* configuration options (see ./plot_config.js for more info)
57+
* @param {object} dynamicBehavior
58+
* object containing Javascript functions that mirror the behavior of options
59+
* in data, layout, and config.
5760
*
5861
* OR
5962
*
@@ -63,7 +66,7 @@ var numericNameWarningCountLimit = 5;
6366
* object containing `data`, `layout`, `config`, and `frames` members
6467
*
6568
*/
66-
function plot(gd, data, layout, config) {
69+
function plot(gd, data, layout, config, dynamicBehavior) {
6770
var frames;
6871

6972
gd = Lib.getGraphDiv(gd);
@@ -79,7 +82,7 @@ function plot(gd, data, layout, config) {
7982
frames = obj.frames;
8083
}
8184

82-
var okToPlot = Events.triggerHandler(gd, 'plotly_beforeplot', [data, layout, config]);
85+
var okToPlot = Events.triggerHandler(gd, 'plotly_beforeplot', [data, layout, config, dynamicBehavior]);
8386
if(okToPlot === false) return Promise.reject();
8487

8588
// if there's no data or layout, and this isn't yet a plotly plot
@@ -88,6 +91,8 @@ function plot(gd, data, layout, config) {
8891
Lib.warn('Calling Plotly.plot as if redrawing ' +
8992
'but this container doesn\'t yet have a plot.', gd);
9093
}
94+
95+
gd.dynamicBehavior = dynamicBehavior || {};
9196

9297
function addFrames() {
9398
if(frames) {
@@ -97,7 +102,7 @@ function plot(gd, data, layout, config) {
97102

98103
// transfer configuration options to gd until we move over to
99104
// a more OO like model
100-
setPlotContext(gd, config);
105+
setPlotContext(gd, config, dynamicBehavior.config);
101106

102107
if(!layout) layout = {};
103108

@@ -136,7 +141,7 @@ function plot(gd, data, layout, config) {
136141
gd.layout = helpers.cleanLayout(layout);
137142
}
138143

139-
Plots.supplyDefaults(gd);
144+
Plots.supplyDefaults(gd, dynamicBehavior);
140145

141146
var fullLayout = gd._fullLayout;
142147
var hasCartesian = fullLayout._has('cartesian');
@@ -405,7 +410,7 @@ function opaqueSetBackground(gd, bgColor) {
405410
setBackground(gd, blend);
406411
}
407412

408-
function setPlotContext(gd, config) {
413+
function setPlotContext(gd, config, dynamicConfig) {
409414
if(!gd._context) {
410415
gd._context = Lib.extendDeep({}, dfltConfig);
411416

@@ -434,6 +439,17 @@ function setPlotContext(gd, config) {
434439
}
435440
}
436441

442+
if (dynamicConfig) {
443+
keys = Object.keys(dynamicConfig);
444+
for(i = 0; i < keys.length; i++) {
445+
key = keys[i];
446+
// Prefer dynamic functions over static options
447+
if(key in context && typeof dynamicConfig[key] === 'function') {
448+
context[key] = dynamicConfig[key];
449+
}
450+
}
451+
}
452+
437453
// map plot3dPixelRatio to plotGlPixelRatio for backward compatibility
438454
if(config.plot3dPixelRatio && !context.plotGlPixelRatio) {
439455
context.plotGlPixelRatio = context.plot3dPixelRatio;
@@ -631,15 +647,16 @@ function redraw(gd) {
631647
* @param {Object[]} data
632648
* @param {Object} layout
633649
* @param {Object} config
650+
* @param {Object} dynamicBehavior
634651
*/
635-
function newPlot(gd, data, layout, config) {
652+
function newPlot(gd, data, layout, config, dynamicBehavior) {
636653
gd = Lib.getGraphDiv(gd);
637654

638655
// remove gl contexts
639656
Plots.cleanPlot([], {}, gd._fullData || [], gd._fullLayout || {});
640657

641658
Plots.purge(gd);
642-
return exports.plot(gd, data, layout, config);
659+
return exports.plot(gd, data, layout, config, dynamicBehavior);
643660
}
644661

645662
/**
@@ -2338,6 +2355,8 @@ function update(gd, traceUpdate, layoutUpdate, _traces) {
23382355
gd = Lib.getGraphDiv(gd);
23392356
helpers.clearPromiseQueue(gd);
23402357

2358+
var dynamicBehavior = gd.dynamicBehavior;
2359+
23412360
if(gd.framework && gd.framework.isPolar) {
23422361
return Promise.resolve(gd);
23432362
}
@@ -2371,7 +2390,7 @@ function update(gd, traceUpdate, layoutUpdate, _traces) {
23712390
seq.push(exports.plot);
23722391
} else {
23732392
seq.push(Plots.previousPromises);
2374-
axRangeSupplyDefaultsByPass(gd, relayoutFlags, relayoutSpecs) || Plots.supplyDefaults(gd);
2393+
axRangeSupplyDefaultsByPass(gd, relayoutFlags, relayoutSpecs) || Plots.supplyDefaults(gd, dynamicBehavior);
23752394

23762395
if(restyleFlags.style) seq.push(subroutines.doTraceStyle);
23772396
if(restyleFlags.colorbars || relayoutFlags.colorbars) seq.push(subroutines.doColorBars);

src/plot_api/subroutines.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ exports.doColorBars = function(gd) {
536536
exports.layoutReplot = function(gd) {
537537
var layout = gd.layout;
538538
gd.layout = undefined;
539-
return Registry.call('plot', gd, '', layout);
539+
return Registry.call('plot', gd, '', layout, gd.dynamicBehavior);
540540
};
541541

542542
exports.doLegend = function(gd) {

src/plots/cartesian/axes.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,9 @@ function numFormat(v, ax, fmtoverride, hover) {
13161316
var tickformat = axes.getTickFormat(ax);
13171317
var separatethousands = ax.separatethousands;
13181318

1319+
// Dynamic tickformat function
1320+
if(typeof tickformat === 'function') return tickformat(v);
1321+
13191322
// special case for hover: set exponent just for this value, and
13201323
// add a couple more digits of precision over tick labels
13211324
if(hover) {

src/plots/plots.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,28 @@ plots.sendDataToCloud = function(gd) {
235235
return false;
236236
};
237237

238+
// Recursively copy any function properties of b into a if a
239+
// already has the corresponding key.
240+
// If a = {key1: "val1", key2: "val2"} and b = {key1: func1, key3: func2},
241+
// sets a to {key1: func1, key2: "val2"}.
242+
function recursivelyCopyFunctions(a, b) {
243+
if(!b) return;
244+
245+
Object.keys(a).forEach(function(key) {
246+
// If a[key] and b[key] are objects, recurse down.
247+
// Note that typeof returns 'object' on arrays.
248+
if(typeof a[key] === 'object') {
249+
if(typeof b[key] === 'object') {
250+
recursivelyCopyFunctions(a[key], b[key]);
251+
}
252+
// If a[key] is anything besides an object and
253+
// b[key] is a funciton, replace a[key] with b[key]
254+
} else if(typeof b[key] === 'function') {
255+
a[key] = b[key];
256+
}
257+
});
258+
}
259+
238260
var d3FormatKeys = [
239261
'days', 'shortDays', 'months', 'shortMonths', 'periods',
240262
'dateTime', 'date', 'time',
@@ -277,10 +299,12 @@ var extraFormatKeys = [
277299
* is a list of all the transform modules invoked.
278300
*
279301
*/
280-
plots.supplyDefaults = function(gd, opts) {
302+
plots.supplyDefaults = function(gd, opts, dynamicBehavior) {
281303
var skipUpdateCalc = opts && opts.skipUpdateCalc;
282304
var oldFullLayout = gd._fullLayout || {};
283305

306+
dynamicBehavior = dynamicBehavior || {};
307+
284308
if(oldFullLayout._skipDefaults) {
285309
delete oldFullLayout._skipDefaults;
286310
return;
@@ -425,7 +449,7 @@ plots.supplyDefaults = function(gd, opts) {
425449
}
426450
}
427451

428-
// finally, fill in the pieces of layout that may need to look at data
452+
// fill in the pieces of layout that may need to look at data
429453
plots.supplyLayoutModuleDefaults(newLayout, newFullLayout, newFullData, gd._transitionData);
430454

431455
// Special cases that introduce interactions between traces.
@@ -465,6 +489,10 @@ plots.supplyDefaults = function(gd, opts) {
465489
// relink / initialize subplot axis objects
466490
plots.linkSubplots(newFullData, newFullLayout, oldFullData, oldFullLayout);
467491

492+
// finally, fill in any functions from dynamicBehavior.data and .layout
493+
recursivelyCopyFunctions(newFullData, dynamicBehavior.data);
494+
recursivelyCopyFunctions(newFullLayout, dynamicBehavior.layout);
495+
468496
// clean subplots and other artifacts from previous plot calls
469497
plots.cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout);
470498

0 commit comments

Comments
 (0)