Skip to content

Commit 4bc8387

Browse files
committed
Command to decide when bindings are simple
1 parent 60dd634 commit 4bc8387

File tree

3 files changed

+140
-13
lines changed

3 files changed

+140
-13
lines changed

src/plots/command.js

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,65 @@ var Lib = require('../lib');
1515
var attrPrefixRegex = /^(data|layout)(\[(-?[0-9]*)\])?\.(.*)$/;
1616

1717
/*
18-
* This function checks to see if a set of bindings is compatible
19-
* with automatic two-way binding. The criteria right now are that
18+
* This function checks to see if an array of objects containing
19+
* method and args properties is compatible with automatic two-way
20+
* binding. The criteria right now are that
2021
*
2122
* 1. multiple traces may be affected
2223
* 2. only one property may be affected
24+
* 3. the same property must be affected by all commands
2325
*/
24-
exports.bindingsAreConsistent = function(currentBindings, newBindings) {
25-
// If they're not both arrays of equal length, return false:
26-
if(!newBindings || !currentBindings || currentBindings.length !== newBindings.length) {
27-
return false;
28-
}
26+
exports.hasSimpleBindings = function(gd, commandList) {
27+
var n = commandList.length;
2928

30-
var n = currentBindings.length;
29+
var refBinding;
3130

3231
for(var i = 0; i < n; i++) {
33-
// This is not the most efficient check, but the pathological case where there
34-
// are an excessive number of bindings should be rare, and at any rate we really
35-
// try to bail out early at every opportunity.
36-
if(currentBindings.indexOf(newBindings[i]) === -1) {
32+
var command = commandList[i];
33+
var method = command.method;
34+
var args = command.args;
35+
36+
// If any command has no method, refuse to bind:
37+
if(!method) {
38+
return false;
39+
}
40+
var bindings = exports.computeAPICommandBindings(gd, method, args);
41+
42+
// Right now, handle one and *only* one property being set:
43+
if(bindings.length !== 1) {
3744
return false;
3845
}
46+
47+
if(!refBinding) {
48+
refBinding = bindings[0];
49+
if(Array.isArray(refBinding.traces)) {
50+
refBinding.traces.sort();
51+
}
52+
} else {
53+
var binding = bindings[0];
54+
if(binding.type !== refBinding.type) {
55+
return false;
56+
}
57+
if(binding.prop !== refBinding.prop) {
58+
return false;
59+
}
60+
if(Array.isArray(refBinding.traces)) {
61+
if(Array.isArray(binding.traces)) {
62+
binding.traces.sort();
63+
for(var j = 0; j < refBinding.traces.length; j++) {
64+
if(refBinding.traces[j] !== binding.traces[j]) {
65+
return false;
66+
}
67+
}
68+
} else {
69+
return false;
70+
}
71+
} else {
72+
if(binding.prop !== refBinding.prop) {
73+
return false;
74+
}
75+
}
76+
}
3977
}
4078

4179
return true;

src/plots/plots.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ var commandModule = require('./command');
4242
plots.executeAPICommand = commandModule.executeAPICommand;
4343
plots.computeAPICommandBindings = commandModule.computeAPICommandBindings;
4444
plots.evaluateAPICommandBinding = commandModule.evaluateAPICommandBinding;
45-
plots.bindingsAreConsistent = commandModule.bindingsAreConsistent;
45+
plots.hasSimpleBindings = commandModule.hasSimpleBindings;
4646

4747
/**
4848
* Find subplot ids in data.

test/jasmine/tests/command_test.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,95 @@ describe('Plots.executeAPICommand', function() {
7575
});
7676
});
7777

78+
describe('Plots.hasSimpleBindings', function() {
79+
'use strict';
80+
var gd;
81+
beforeEach(function() {
82+
gd = createGraphDiv();
83+
84+
Plotly.plot(gd, [
85+
{x: [1, 2, 3], y: [1, 2, 3]},
86+
{x: [1, 2, 3], y: [4, 5, 6]},
87+
]);
88+
});
89+
90+
afterEach(function() {
91+
destroyGraphDiv(gd);
92+
});
93+
94+
it('return true when bindings are simple', function() {
95+
var isSimple = Plots.hasSimpleBindings(gd, [{
96+
method: 'restyle',
97+
args: [{'marker.size': 10}]
98+
}, {
99+
method: 'restyle',
100+
args: [{'marker.size': 20}]
101+
}]);
102+
103+
expect(isSimple).toBe(true);
104+
});
105+
106+
it('return false when properties are not the same', function() {
107+
var isSimple = Plots.hasSimpleBindings(gd, [{
108+
method: 'restyle',
109+
args: [{'marker.size': 10}]
110+
}, {
111+
method: 'restyle',
112+
args: [{'marker.color': 20}]
113+
}]);
114+
115+
expect(isSimple).toBe(false);
116+
});
117+
118+
it('return false when a command binds to more than one property', function() {
119+
var isSimple = Plots.hasSimpleBindings(gd, [{
120+
method: 'restyle',
121+
args: [{'marker.color': 10, 'marker.size': 12}]
122+
}, {
123+
method: 'restyle',
124+
args: [{'marker.color': 20}]
125+
}]);
126+
127+
expect(isSimple).toBe(false);
128+
});
129+
130+
it('return false when commands affect different traces', function() {
131+
var isSimple = Plots.hasSimpleBindings(gd, [{
132+
method: 'restyle',
133+
args: [{'marker.color': 10}, [0]]
134+
}, {
135+
method: 'restyle',
136+
args: [{'marker.color': 20}, [1]]
137+
}]);
138+
139+
expect(isSimple).toBe(false);
140+
});
141+
142+
it('return true when commands affect the same traces', function() {
143+
var isSimple = Plots.hasSimpleBindings(gd, [{
144+
method: 'restyle',
145+
args: [{'marker.color': 10}, [1]]
146+
}, {
147+
method: 'restyle',
148+
args: [{'marker.color': 20}, [1]]
149+
}]);
150+
151+
expect(isSimple).toBe(true);
152+
});
153+
154+
it('return true when commands affect the same traces in different order', function() {
155+
var isSimple = Plots.hasSimpleBindings(gd, [{
156+
method: 'restyle',
157+
args: [{'marker.color': 10}, [1, 2]]
158+
}, {
159+
method: 'restyle',
160+
args: [{'marker.color': 20}, [2, 1]]
161+
}]);
162+
163+
expect(isSimple).toBe(true);
164+
});
165+
});
166+
78167
describe('Plots.computeAPICommandBindings', function() {
79168
'use strict';
80169

0 commit comments

Comments
 (0)