Skip to content

Commit a107466

Browse files
committed
fix #358 - restyling orientation
1 parent 7ec1634 commit a107466

File tree

6 files changed

+171
-87
lines changed

6 files changed

+171
-87
lines changed

src/plot_api/plot_api.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,13 @@ function _restyle(gd, aobj, traces) {
14991499
// before we swap everything else
15001500
if(ai === 'orientation') {
15011501
param.set(newVal);
1502-
if(param.get() === undoit[ai][i]) continue;
1502+
// obnoxious that we need this level of coupling... but in order to
1503+
// properly handle setting orientation to `null` we need to mimic
1504+
// the logic inside Bars.supplyDefaults for default orientation
1505+
var defaultOrientation = (cont.x && !cont.y) ? 'h' : 'v';
1506+
if((param.get() || defaultOrientation) === contFull.orientation) {
1507+
continue;
1508+
}
15031509
}
15041510
// orientationaxes has no value,
15051511
// it flips everything and the axes
@@ -1508,6 +1514,7 @@ function _restyle(gd, aobj, traces) {
15081514
{v: 'h', h: 'v'}[contFull.orientation];
15091515
}
15101516
helpers.swapXYData(cont);
1517+
flags.calc = flags.clearAxisTypes = true;
15111518
}
15121519
else if(Plots.dataArrayContainers.indexOf(param.parts[0]) !== -1) {
15131520
// TODO: use manageArrays.applyContainerArrayChanges here too

test/jasmine/assets/check_ticks.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
var d3 = require('d3');
4+
5+
module.exports = function checkTicks(axLetter, vals, msg) {
6+
var selection = d3.selectAll('.' + axLetter + 'tick text');
7+
expect(selection.size()).toBe(vals.length);
8+
selection.each(function(d, i) {
9+
expect(d3.select(this).text()).toBe(vals[i], msg + ': ' + i);
10+
});
11+
};

test/jasmine/assets/negate_if.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
/**
4+
* Conditionally negate an expectation:
5+
*
6+
* negateIf(expect(x), xIsSomethingElse).toBe(0);
7+
*
8+
* is equivalent to:
9+
*
10+
* if(xIsSomethingElse) expect(x).not.toBe(0);
11+
* else expect(x).toBe(0);
12+
*/
13+
module.exports = function negateIf(expectation, negate) {
14+
if(negate) return expectation.not;
15+
return expectation;
16+
};

test/jasmine/tests/bar_test.js

+130-62
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ var createGraphDiv = require('../assets/create_graph_div');
1111
var destroyGraphDiv = require('../assets/destroy_graph_div');
1212
var fail = require('../assets/fail_test');
1313
var customMatchers = require('../assets/custom_matchers');
14+
var checkTicks = require('../assets/check_ticks');
15+
var negateIf = require('../assets/negate_if');
16+
17+
var d3 = require('d3');
1418

1519
describe('Bar.supplyDefaults', function() {
1620
'use strict';
@@ -762,10 +766,16 @@ describe('Bar.setPositions', function() {
762766
describe('A bar plot', function() {
763767
'use strict';
764768

769+
var gd;
770+
765771
beforeAll(function() {
766772
jasmine.addMatchers(customMatchers);
767773
});
768774

775+
beforeEach(function() {
776+
gd = createGraphDiv();
777+
});
778+
769779
afterEach(destroyGraphDiv);
770780

771781
function getAllTraceNodes(node) {
@@ -830,15 +840,13 @@ describe('A bar plot', function() {
830840
}
831841

832842
it('should show bar texts (inside case)', function(done) {
833-
var gd = createGraphDiv(),
834-
data = [{
835-
y: [10, 20, 30],
836-
type: 'bar',
837-
text: ['1', 'Very very very very very long bar text'],
838-
textposition: 'inside',
839-
}],
840-
layout = {
841-
};
843+
var data = [{
844+
y: [10, 20, 30],
845+
type: 'bar',
846+
text: ['1', 'Very very very very very long bar text'],
847+
textposition: 'inside',
848+
}];
849+
var layout = {};
842850

843851
Plotly.plot(gd, data, layout).then(function() {
844852
var traceNodes = getAllTraceNodes(gd),
@@ -862,16 +870,15 @@ describe('A bar plot', function() {
862870
});
863871

864872
it('should show bar texts (outside case)', function(done) {
865-
var gd = createGraphDiv(),
866-
data = [{
867-
y: [10, -20, 30],
868-
type: 'bar',
869-
text: ['1', 'Very very very very very long bar text'],
870-
textposition: 'outside',
871-
}],
872-
layout = {
873-
barmode: 'relative'
874-
};
873+
var data = [{
874+
y: [10, -20, 30],
875+
type: 'bar',
876+
text: ['1', 'Very very very very very long bar text'],
877+
textposition: 'outside',
878+
}];
879+
var layout = {
880+
barmode: 'relative'
881+
};
875882

876883
Plotly.plot(gd, data, layout).then(function() {
877884
var traceNodes = getAllTraceNodes(gd),
@@ -896,15 +903,13 @@ describe('A bar plot', function() {
896903
});
897904

898905
it('should show bar texts (horizontal case)', function(done) {
899-
var gd = createGraphDiv(),
900-
data = [{
901-
x: [10, -20, 30],
902-
type: 'bar',
903-
text: ['Very very very very very long bar text', -20],
904-
textposition: 'outside',
905-
}],
906-
layout = {
907-
};
906+
var data = [{
907+
x: [10, -20, 30],
908+
type: 'bar',
909+
text: ['Very very very very very long bar text', -20],
910+
textposition: 'outside',
911+
}];
912+
var layout = {};
908913

909914
Plotly.plot(gd, data, layout).then(function() {
910915
var traceNodes = getAllTraceNodes(gd),
@@ -929,17 +934,16 @@ describe('A bar plot', function() {
929934
});
930935

931936
it('should show bar texts (barnorm case)', function(done) {
932-
var gd = createGraphDiv(),
933-
data = [{
934-
x: [100, -100, 100],
935-
type: 'bar',
936-
text: [100, -100, 100],
937-
textposition: 'outside',
938-
}],
939-
layout = {
940-
barmode: 'relative',
941-
barnorm: 'percent'
942-
};
937+
var data = [{
938+
x: [100, -100, 100],
939+
type: 'bar',
940+
text: [100, -100, 100],
941+
textposition: 'outside',
942+
}];
943+
var layout = {
944+
barmode: 'relative',
945+
barnorm: 'percent'
946+
};
943947

944948
Plotly.plot(gd, data, layout).then(function() {
945949
var traceNodes = getAllTraceNodes(gd),
@@ -964,8 +968,7 @@ describe('A bar plot', function() {
964968
});
965969

966970
it('should be able to restyle', function(done) {
967-
var gd = createGraphDiv(),
968-
mock = Lib.extendDeep({}, require('@mocks/bar_attrs_relative'));
971+
var mock = Lib.extendDeep({}, require('@mocks/bar_attrs_relative'));
969972

970973
Plotly.plot(gd, mock.data, mock.layout).then(function() {
971974
var cd = gd.calcdata;
@@ -1114,27 +1117,26 @@ describe('A bar plot', function() {
11141117
});
11151118

11161119
it('should coerce text-related attributes', function(done) {
1117-
var gd = createGraphDiv(),
1118-
data = [{
1119-
y: [10, 20, 30, 40],
1120-
type: 'bar',
1121-
text: ['T1P1', 'T1P2', 13, 14],
1122-
textposition: ['inside', 'outside', 'auto', 'BADVALUE'],
1123-
textfont: {
1124-
family: ['"comic sans"'],
1125-
color: ['red', 'green'],
1126-
},
1127-
insidetextfont: {
1128-
size: [8, 12, 16],
1129-
color: ['black'],
1130-
},
1131-
outsidetextfont: {
1132-
size: [null, 24, 32]
1133-
}
1134-
}],
1135-
layout = {
1136-
font: {family: 'arial', color: 'blue', size: 13}
1137-
};
1120+
var data = [{
1121+
y: [10, 20, 30, 40],
1122+
type: 'bar',
1123+
text: ['T1P1', 'T1P2', 13, 14],
1124+
textposition: ['inside', 'outside', 'auto', 'BADVALUE'],
1125+
textfont: {
1126+
family: ['"comic sans"'],
1127+
color: ['red', 'green'],
1128+
},
1129+
insidetextfont: {
1130+
size: [8, 12, 16],
1131+
color: ['black'],
1132+
},
1133+
outsidetextfont: {
1134+
size: [null, 24, 32]
1135+
}
1136+
}];
1137+
var layout = {
1138+
font: {family: 'arial', color: 'blue', size: 13}
1139+
};
11381140

11391141
var expected = {
11401142
y: [10, 20, 30, 40],
@@ -1194,6 +1196,72 @@ describe('A bar plot', function() {
11941196
.catch(fail)
11951197
.then(done);
11961198
});
1199+
1200+
it('can change orientation and correctly sets axis types', function(done) {
1201+
function checkBarsMatch(dims, msg) {
1202+
var bars = d3.selectAll('.bars .point');
1203+
var bbox1 = bars.node().getBoundingClientRect();
1204+
bars.each(function(d, i) {
1205+
if(!i) return;
1206+
var bbox = this.getBoundingClientRect();
1207+
['left', 'right', 'top', 'bottom', 'width', 'height'].forEach(function(dim) {
1208+
negateIf(expect(bbox[dim]), dims.indexOf(dim) === -1)
1209+
.toBeWithin(bbox1[dim], 0.1, msg + ' (' + i + '): ' + dim);
1210+
});
1211+
});
1212+
}
1213+
1214+
Plotly.newPlot(gd, [{
1215+
x: ['a', 'b', 'c'],
1216+
y: [1, 2, 3],
1217+
type: 'bar'
1218+
}], {
1219+
width: 400, height: 400
1220+
})
1221+
.then(function() {
1222+
checkTicks('x', ['a', 'b', 'c'], 'initial x');
1223+
checkTicks('y', ['0', '0.5', '1', '1.5', '2', '2.5', '3'], 'initial y');
1224+
1225+
checkBarsMatch(['bottom', 'width'], 'initial');
1226+
1227+
// turn implicit "v" into explicit "v" - a noop but specifically
1228+
// for orientation this was broken at one point...
1229+
return Plotly.restyle(gd, {orientation: 'v'});
1230+
})
1231+
.then(function() {
1232+
checkTicks('x', ['a', 'b', 'c'], 'explicit v x');
1233+
checkTicks('y', ['0', '0.5', '1', '1.5', '2', '2.5', '3'], 'explicit v y');
1234+
1235+
checkBarsMatch(['bottom', 'width'], 'explicit v');
1236+
1237+
// back to implicit v
1238+
return Plotly.restyle(gd, {orientation: null});
1239+
})
1240+
.then(function() {
1241+
checkTicks('x', ['a', 'b', 'c'], 'implicit v x');
1242+
checkTicks('y', ['0', '0.5', '1', '1.5', '2', '2.5', '3'], 'implicit v y');
1243+
1244+
checkBarsMatch(['bottom', 'width'], 'implicit v');
1245+
1246+
return Plotly.restyle(gd, {orientation: 'h'});
1247+
})
1248+
.then(function() {
1249+
checkTicks('x', ['0', '1', '2', '3'], 'h x');
1250+
checkTicks('y', ['a', 'b', 'c'], 'h y');
1251+
1252+
checkBarsMatch(['left', 'height'], 'initial');
1253+
1254+
return Plotly.restyle(gd, {orientation: 'v'});
1255+
})
1256+
.then(function() {
1257+
checkTicks('x', ['a', 'b', 'c'], 'final x');
1258+
checkTicks('y', ['0', '0.5', '1', '1.5', '2', '2.5', '3'], 'final y');
1259+
1260+
checkBarsMatch(['bottom', 'width'], 'final');
1261+
})
1262+
.catch(fail)
1263+
.then(done);
1264+
});
11971265
});
11981266

11991267
describe('bar hover', function() {

test/jasmine/tests/contour_test.js

+1-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var fail = require('../assets/fail_test');
1010
var createGraphDiv = require('../assets/create_graph_div');
1111
var destroyGraphDiv = require('../assets/destroy_graph_div');
1212
var customMatchers = require('../assets/custom_matchers');
13+
var checkTicks = require('../assets/check_ticks');
1314

1415
var d3 = require('d3');
1516

@@ -359,14 +360,6 @@ describe('contour edits', function() {
359360
});
360361
afterEach(destroyGraphDiv);
361362

362-
function checkTicks(axLetter, vals, msg) {
363-
var selection = d3.selectAll('.' + axLetter + 'tick text');
364-
expect(selection.size()).toBe(vals.length);
365-
selection.each(function(d, i) {
366-
expect(d3.select(this).text()).toBe(vals[i], msg + ': ' + i);
367-
});
368-
}
369-
370363
it('can restyle x/y to different types', function(done) {
371364
Plotly.newPlot(gd, [{
372365
type: 'contour',

test/jasmine/tests/plot_api_test.js

+5-16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ var customMatchers = require('../assets/custom_matchers');
1616
var createGraphDiv = require('../assets/create_graph_div');
1717
var destroyGraphDiv = require('../assets/destroy_graph_div');
1818
var fail = require('../assets/fail_test');
19+
var checkTicks = require('../assets/check_ticks');
20+
var negateIf = require('../assets/negate_if');
1921

2022

2123
describe('Test plot api', function() {
@@ -907,11 +909,6 @@ describe('Test plot api', function() {
907909
.then(done);
908910
});
909911

910-
function negateIf(condition, negate) {
911-
if(negate) return condition.not;
912-
return condition;
913-
}
914-
915912
it('turns off zauto when you edit zmin or zmax', function(done) {
916913
var zmin0 = 2;
917914
var zmax1 = 10;
@@ -1184,31 +1181,23 @@ describe('Test plot api', function() {
11841181
});
11851182

11861183
it('updates box position and axis type when it falls back to name', function(done) {
1187-
function checkXTicks(vals, msg) {
1188-
var selection = d3.selectAll('.xtick');
1189-
expect(selection.size()).toBe(vals.length);
1190-
selection.each(function(d, i) {
1191-
expect(d3.select(this).text()).toBe(vals[i], msg + ': ' + i);
1192-
});
1193-
}
1194-
11951184
Plotly.newPlot(gd, [{name: 'A', y: [1, 2, 3, 4, 5], type: 'box'}],
11961185
{width: 400, height: 400, xaxis: {nticks: 3}}
11971186
)
11981187
.then(function() {
1199-
checkXTicks(['A'], 'initial');
1188+
checkTicks('x', ['A'], 'initial');
12001189
expect(gd._fullLayout.xaxis.type).toBe('category');
12011190

12021191
return Plotly.restyle(gd, {name: 'B'});
12031192
})
12041193
.then(function() {
1205-
checkXTicks(['B'], 'changed category');
1194+
checkTicks('x', ['B'], 'changed category');
12061195
expect(gd._fullLayout.xaxis.type).toBe('category');
12071196

12081197
return Plotly.restyle(gd, {x0: 12.3});
12091198
})
12101199
.then(function() {
1211-
checkXTicks(['12', '12.5'], 'switched to numeric');
1200+
checkTicks('x', ['12', '12.5'], 'switched to numeric');
12121201
expect(gd._fullLayout.xaxis.type).toBe('linear');
12131202
})
12141203
.catch(fail)

0 commit comments

Comments
 (0)