Skip to content

Commit a775325

Browse files
authored
Merge pull request #2285 from plotly/carpet-title
fix the title side for odd cheaterslope situations
2 parents 2db8707 + 0c7d20e commit a775325

File tree

5 files changed

+502
-12
lines changed

5 files changed

+502
-12
lines changed

src/traces/carpet/plot.js

+40-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ var map1dArray = require('./map_1d_array');
1515
var makepath = require('./makepath');
1616
var orientText = require('./orient_text');
1717
var svgTextUtils = require('../../lib/svg_text_utils');
18+
var Lib = require('../../lib');
19+
var alignmentConstants = require('../../constants/alignment');
1820

1921
module.exports = function plot(gd, plotinfo, cdcarpet) {
2022
for(var i = 0; i < cdcarpet.length; i++) {
@@ -58,10 +60,10 @@ function plotOne(gd, plotinfo, cd) {
5860
drawGridLines(xa, ya, boundaryLayer, aax, 'a-boundary', aax._boundarylines);
5961
drawGridLines(xa, ya, boundaryLayer, bax, 'b-boundary', bax._boundarylines);
6062

61-
var maxAExtent = drawAxisLabels(gd, xa, ya, trace, t, labelLayer, aax._labels, 'a-label');
62-
var maxBExtent = drawAxisLabels(gd, xa, ya, trace, t, labelLayer, bax._labels, 'b-label');
63+
var labelOrientationA = drawAxisLabels(gd, xa, ya, trace, t, labelLayer, aax._labels, 'a-label');
64+
var labelOrientationB = drawAxisLabels(gd, xa, ya, trace, t, labelLayer, bax._labels, 'b-label');
6365

64-
drawAxisTitles(gd, labelLayer, trace, t, xa, ya, maxAExtent, maxBExtent);
66+
drawAxisTitles(gd, labelLayer, trace, t, xa, ya, labelOrientationA, labelOrientationB);
6567

6668
drawClipPath(trace, t, clipLayer, xa, ya);
6769
}
@@ -131,8 +133,9 @@ function drawAxisLabels(gd, xaxis, yaxis, trace, t, layer, labels, labelClass) {
131133
.classed(labelClass, true);
132134

133135
var maxExtent = 0;
136+
var labelOrientation = {};
134137

135-
labelJoin.each(function(label) {
138+
labelJoin.each(function(label, i) {
136139
// Most of the positioning is done in calc_labels. Only the parts that depend upon
137140
// the screen space representation of the x and y axes are here:
138141
var orientation;
@@ -142,6 +145,11 @@ function drawAxisLabels(gd, xaxis, yaxis, trace, t, layer, labels, labelClass) {
142145
var angle = (label.axis.tickangle + 180.0) * Math.PI / 180.0;
143146
orientation = orientText(trace, xaxis, yaxis, label.xy, [Math.cos(angle), Math.sin(angle)]);
144147
}
148+
149+
if(!i) {
150+
// TODO: offsetMultiplier? Not currently used anywhere...
151+
labelOrientation = {angle: orientation.angle, flip: orientation.flip};
152+
}
145153
var direction = (label.endAnchor ? -1 : 1) * orientation.flip;
146154

147155
var labelEl = d3.select(this)
@@ -169,29 +177,40 @@ function drawAxisLabels(gd, xaxis, yaxis, trace, t, layer, labels, labelClass) {
169177

170178
labelJoin.exit().remove();
171179

172-
return maxExtent;
180+
labelOrientation.maxExtent = maxExtent;
181+
return labelOrientation;
173182
}
174183

175-
function drawAxisTitles(gd, layer, trace, t, xa, ya, maxAExtent, maxBExtent) {
184+
function drawAxisTitles(gd, layer, trace, t, xa, ya, labelOrientationA, labelOrientationB) {
176185
var a, b, xy, dxy;
177186

178187
a = 0.5 * (trace.a[0] + trace.a[trace.a.length - 1]);
179188
b = trace.b[0];
180189
xy = trace.ab2xy(a, b, true);
181190
dxy = trace.dxyda_rough(a, b);
182-
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.aaxis, xa, ya, maxAExtent, 'a-title');
191+
if(labelOrientationA.angle === undefined) {
192+
Lib.extendFlat(labelOrientationA, orientText(trace, xa, ya, xy, trace.dxydb_rough(a, b)));
193+
}
194+
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.aaxis, xa, ya, labelOrientationA, 'a-title');
183195

184196
a = trace.a[0];
185197
b = 0.5 * (trace.b[0] + trace.b[trace.b.length - 1]);
186198
xy = trace.ab2xy(a, b, true);
187199
dxy = trace.dxydb_rough(a, b);
188-
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.baxis, xa, ya, maxBExtent, 'b-title');
200+
if(labelOrientationB.angle === undefined) {
201+
Lib.extendFlat(labelOrientationB, orientText(trace, xa, ya, xy, trace.dxyda_rough(a, b)));
202+
}
203+
drawAxisTitle(gd, layer, trace, t, xy, dxy, trace.baxis, xa, ya, labelOrientationB, 'b-title');
189204
}
190205

191-
function drawAxisTitle(gd, layer, trace, t, xy, dxy, axis, xa, ya, offset, labelClass) {
206+
var lineSpacing = alignmentConstants.LINE_SPACING;
207+
var midShift = ((1 - alignmentConstants.MID_SHIFT) / lineSpacing) + 1;
208+
209+
function drawAxisTitle(gd, layer, trace, t, xy, dxy, axis, xa, ya, labelOrientation, labelClass) {
192210
var data = [];
193211
if(axis.title) data.push(axis.title);
194212
var titleJoin = layer.selectAll('text.' + labelClass).data(data);
213+
var offset = labelOrientation.maxExtent;
195214

196215
titleJoin.enter().append('text')
197216
.classed(labelClass, true);
@@ -205,14 +224,23 @@ function drawAxisTitle(gd, layer, trace, t, xy, dxy, axis, xa, ya, offset, label
205224
}
206225

207226
// In addition to the size of the labels, add on some extra padding:
208-
offset += axis.titlefont.size + axis.titleoffset;
227+
var titleSize = axis.titlefont.size;
228+
offset += titleSize + axis.titleoffset;
209229

230+
var labelNorm = labelOrientation.angle + (labelOrientation.flip < 0 ? 180 : 0);
231+
var angleDiff = (labelNorm - orientation.angle + 450) % 360;
232+
var reverseTitle = angleDiff > 90 && angleDiff < 270;
210233

211234
var el = d3.select(this);
212235

213236
el.text(axis.title || '')
214-
.call(svgTextUtils.convertToTspans, gd)
215-
.attr('transform',
237+
.call(svgTextUtils.convertToTspans, gd);
238+
239+
if(reverseTitle) {
240+
offset = (-svgTextUtils.lineCount(el) + midShift) * lineSpacing * titleSize - offset;
241+
}
242+
243+
el.attr('transform',
216244
'translate(' + orientation.p[0] + ',' + orientation.p[1] + ') ' +
217245
'rotate(' + orientation.angle + ') ' +
218246
'translate(0,' + offset + ')'

test/image/baselines/cheaterslope.png

87.2 KB
Loading
Loading

test/image/mocks/cheaterslope.json

+231
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
{
2+
"data": [
3+
{
4+
"type": "carpet",
5+
"carpet": "c1",
6+
"a": [1, 2, 3],
7+
"b": [1, 2, 3],
8+
"y": [[0, 0.8, 2], [1.2, 2, 3.2], [2, 2.8, 4]],
9+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
10+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
11+
"xaxis": "x",
12+
"yaxis": "y",
13+
"cheaterslope": -10
14+
},
15+
{
16+
"type": "carpet",
17+
"carpet": "c2",
18+
"a": [1, 2, 3],
19+
"b": [1, 2, 3],
20+
"y": [[0.8, 0, 2], [2, 1.2, 3.2], [2.8, 2, 4]],
21+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
22+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
23+
"xaxis": "x2",
24+
"yaxis": "y",
25+
"cheaterslope": -10
26+
},
27+
{
28+
"type": "carpet",
29+
"carpet": "c3",
30+
"a": [1, 2, 3],
31+
"b": [1, 2, 3],
32+
"y": [[0, 0.8, 2], [1.2, 2, 3.2], [2, 2.8, 4]],
33+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
34+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
35+
"xaxis": "x",
36+
"yaxis": "y2",
37+
"cheaterslope": -0.3
38+
},
39+
{
40+
"type": "carpet",
41+
"carpet": "c4",
42+
"a": [1, 2, 3],
43+
"b": [1, 2, 3],
44+
"y": [[0.8, 0, 2], [2, 1.2, 3.2], [2.8, 2, 4]],
45+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
46+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
47+
"xaxis": "x2",
48+
"yaxis": "y2",
49+
"cheaterslope": -0.3
50+
},
51+
{
52+
"type": "carpet",
53+
"carpet": "c5",
54+
"a": [1, 2, 3],
55+
"b": [1, 2, 3],
56+
"y": [[0, 0.8, 2], [1.2, 2, 3.2], [2, 2.8, 4]],
57+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
58+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
59+
"xaxis": "x",
60+
"yaxis": "y3",
61+
"cheaterslope": 0
62+
},
63+
{
64+
"type": "carpet",
65+
"carpet": "c6",
66+
"a": [1, 2, 3],
67+
"b": [1, 2, 3],
68+
"y": [[0.8, 0, 2], [2, 1.2, 3.2], [2.8, 2, 4]],
69+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
70+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
71+
"xaxis": "x2",
72+
"yaxis": "y3",
73+
"cheaterslope": 0
74+
},
75+
{
76+
"type": "carpet",
77+
"carpet": "c7",
78+
"a": [1, 2, 3],
79+
"b": [1, 2, 3],
80+
"y": [[0, 0.8, 2], [1.2, 2, 3.2], [2, 2.8, 4]],
81+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
82+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
83+
"xaxis": "x",
84+
"yaxis": "y4",
85+
"cheaterslope": 0.3
86+
},
87+
{
88+
"type": "carpet",
89+
"carpet": "c8",
90+
"a": [1, 2, 3],
91+
"b": [1, 2, 3],
92+
"y": [[0.8, 0, 2], [2, 1.2, 3.2], [2.8, 2, 4]],
93+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
94+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
95+
"xaxis": "x2",
96+
"yaxis": "y4",
97+
"cheaterslope": 0.3
98+
},
99+
{
100+
"type": "carpet",
101+
"carpet": "c9",
102+
"a": [1, 2, 3],
103+
"b": [1, 2, 3],
104+
"y": [[0, 0.8, 2], [1.2, 2, 3.2], [2, 2.8, 4]],
105+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
106+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
107+
"xaxis": "x",
108+
"yaxis": "y5",
109+
"cheaterslope": 10
110+
},
111+
{
112+
"type": "carpet",
113+
"carpet": "c10",
114+
"a": [1, 2, 3],
115+
"b": [1, 2, 3],
116+
"y": [[0.8, 0, 2], [2, 1.2, 3.2], [2.8, 2, 4]],
117+
"aaxis": {"smoothing": 1, "title": "A axis<br>title", "color": "red"},
118+
"baxis": {"smoothing": 1, "title": "B axis<br>title"},
119+
"xaxis": "x2",
120+
"yaxis": "y5",
121+
"cheaterslope": 10
122+
}
123+
],
124+
"layout": {
125+
"title": "Cheaterslope with titles",
126+
"width": 600,
127+
"height": 800,
128+
"dragmode": "pan",
129+
"margin": {
130+
"t": 60,
131+
"r": 30,
132+
"b": 30,
133+
"l": 30
134+
},
135+
"yaxis": {
136+
"domain": [0, 0.19],
137+
"zeroline": false,
138+
"range": [-2, 5]
139+
},
140+
"yaxis2": {
141+
"domain": [0.21, 0.39],
142+
"zeroline": false,
143+
"range": [-2, 5]
144+
},
145+
"yaxis3": {
146+
"domain": [0.41, 0.59],
147+
"zeroline": false,
148+
"range": [-2, 5]
149+
},
150+
"yaxis4": {
151+
"domain": [0.61, 0.79],
152+
"zeroline": false,
153+
"range": [-2, 5]
154+
},
155+
"yaxis5": {
156+
"domain": [0.81, 1],
157+
"zeroline": false,
158+
"range": [-2, 5]
159+
},
160+
"xaxis": {
161+
"domain": [0, 0.49],
162+
"range": [-0.5, 1.2]
163+
},
164+
"xaxis2": {
165+
"domain": [0.51, 1.0],
166+
"range": [-0.5, 1.2]
167+
},
168+
"annotations": [
169+
{
170+
"x": 0,
171+
"y": 4.5,
172+
"text": "slope: -10",
173+
"align": "left",
174+
"xref": "x",
175+
"yref": "y",
176+
"showarrow": false,
177+
"font": {
178+
"size": 14
179+
}
180+
},
181+
{
182+
"x": 0,
183+
"align": "left",
184+
"y": 4.5,
185+
"xref": "x",
186+
"yref": "y2",
187+
"text": "slope: -0.3",
188+
"showarrow": false,
189+
"font": {
190+
"size": 14
191+
}
192+
},
193+
{
194+
"x": 0,
195+
"y": 4.5,
196+
"align": "left",
197+
"xref": "x",
198+
"yref": "y3",
199+
"text": "slope: 0",
200+
"showarrow": false,
201+
"font": {
202+
"size": 14
203+
}
204+
},
205+
{
206+
"x": 0,
207+
"y": 4.5,
208+
"align": "left",
209+
"xref": "x",
210+
"yref": "y4",
211+
"text": "slope: 0.3",
212+
"showarrow": false,
213+
"font": {
214+
"size": 14
215+
}
216+
},
217+
{
218+
"x": 0,
219+
"y": 4.5,
220+
"align": "left",
221+
"xref": "x",
222+
"yref": "y5",
223+
"text": "slope: 10",
224+
"showarrow": false,
225+
"font": {
226+
"size": 14
227+
}
228+
}
229+
]
230+
}
231+
}

0 commit comments

Comments
 (0)