diff --git a/src/lib/index.js b/src/lib/index.js index f7f9434597f..6039e420d2b 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1184,6 +1184,13 @@ lib.isHidden = function(gd) { /** Return transform text for bar bar-like rectangles and pie-like slices * @param {object} transform + * - targetX: desired position on the x-axis + * - targetY: desired position on the y-axis + * - textX: width of text + * - textY: height of text + * - scale: (optional) scale applied after translate + * - rotate: (optional) rotation applied after scale + * - noCenter: when defined no extra arguments needed in rotation */ lib.getTextTransform = function(transform) { var noCenter = transform.noCenter; diff --git a/src/traces/pie/plot.js b/src/traces/pie/plot.js index ca4490608b6..f1b06621126 100644 --- a/src/traces/pie/plot.js +++ b/src/traces/pie/plot.js @@ -568,25 +568,7 @@ function transformInsideText(textBB, pt, cd0) { var isCircle = (ring === 1) && (Math.abs(pt.startangle - pt.stopangle) === Math.PI * 2); var allTransforms = []; - if(isCircle || isAuto || isHorizontal) { - // max size text can be inserted inside without rotating it - // this inscribes the text rectangle in a circle, which is then inscribed - // in the slice, so it will be an underestimate, which some day we may want - // to improve so this case can get more use - var transform = { - scale: rInscribed * r * 2 / textDiameter, - - // and the center position and rotation in this case - rCenter: 1 - rInscribed, - rotate: 0 - }; - - if(transform.scale >= 1) return transform; - - allTransforms.push(transform); - } - - if(isHorizontal) { + if(!isAuto) { // max size if text is placed (horizontally) at the top or bottom of the arc var considerCrossing = function(angle, key) { @@ -608,12 +590,40 @@ function transformInsideText(textBB, pt, cd0) { } }; - for(var i = 3; i >= -3; i--) { // to cover all cases with trace.rotation added - considerCrossing(Math.PI * i, 'tan'); - considerCrossing(Math.PI * (i + 0.5), 'rad'); + // to cover all cases with trace.rotation added + var i; + if(isHorizontal || isTangential) { + // top + for(i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * i, 'tan'); + // bottom + for(i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 1), 'tan'); + } + if(isHorizontal || isRadial) { + // left + for(i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 1.5), 'rad'); + // right + for(i = 4; i >= -4; i -= 2) considerCrossing(Math.PI * (i + 0.5), 'rad'); } } + if(isCircle || isAuto || isHorizontal) { + // max size text can be inserted inside without rotating it + // this inscribes the text rectangle in a circle, which is then inscribed + // in the slice, so it will be an underestimate, which some day we may want + // to improve so this case can get more use + var transform = { + scale: rInscribed * r * 2 / textDiameter, + + // and the center position and rotation in this case + rCenter: 1 - rInscribed, + rotate: 0 + }; + + if(transform.scale >= 1) return transform; + + allTransforms.push(transform); + } + if(isAuto || isRadial) { allTransforms.push(calcRadTransform(textBB, r, ring, halfAngle, midAngle)); } @@ -622,16 +632,29 @@ function transformInsideText(textBB, pt, cd0) { allTransforms.push(calcTanTransform(textBB, r, ring, halfAngle, midAngle)); } - var maxScaleTransform = allTransforms.sort(function(a, b) { - return b.scale - a.scale; - })[0]; + var id = 0; + var maxScale = 0; + for(var k = 0; k < allTransforms.length; k++) { + var s = allTransforms[k].scale; + if(maxScale < s) { + maxScale = s; + id = k; + } + + if(!isAuto && maxScale >= 1) { + // respect test order for non-auto options + break; + } + } + + var selTransform = allTransforms[id]; - if(maxScaleTransform.pxtxt) { + if(selTransform.pxtxt) { // copy text position if not at the middle - pt.pxtxt = maxScaleTransform.pxtxt; + pt.pxtxt = selTransform.pxtxt; } - return maxScaleTransform; + return selTransform; } function isCrossing(pt, angle) { diff --git a/test/image/baselines/sunburst_inside-text-orientation.png b/test/image/baselines/sunburst_inside-text-orientation.png index fbdc988d3f7..a77ba3102ea 100644 Binary files a/test/image/baselines/sunburst_inside-text-orientation.png and b/test/image/baselines/sunburst_inside-text-orientation.png differ diff --git a/test/image/baselines/sunburst_inside-text-orientation_clock.png b/test/image/baselines/sunburst_inside-text-orientation_clock.png new file mode 100644 index 00000000000..28ab975ef98 Binary files /dev/null and b/test/image/baselines/sunburst_inside-text-orientation_clock.png differ diff --git a/test/image/baselines/sunburst_with-without_values.png b/test/image/baselines/sunburst_with-without_values.png index 80263d41d03..a00afc950f4 100644 Binary files a/test/image/baselines/sunburst_with-without_values.png and b/test/image/baselines/sunburst_with-without_values.png differ diff --git a/test/image/baselines/uniformtext_pie_8_horizontal.png b/test/image/baselines/uniformtext_pie_8_horizontal.png index f043dd63df2..8847a079d5f 100644 Binary files a/test/image/baselines/uniformtext_pie_8_horizontal.png and b/test/image/baselines/uniformtext_pie_8_horizontal.png differ diff --git a/test/image/baselines/uniformtext_pie_8_radial.png b/test/image/baselines/uniformtext_pie_8_radial.png new file mode 100644 index 00000000000..67ab4369d93 Binary files /dev/null and b/test/image/baselines/uniformtext_pie_8_radial.png differ diff --git a/test/image/baselines/uniformtext_pie_8_tangential.png b/test/image/baselines/uniformtext_pie_8_tangential.png new file mode 100644 index 00000000000..d8b2075be3b Binary files /dev/null and b/test/image/baselines/uniformtext_pie_8_tangential.png differ diff --git a/test/image/baselines/uniformtext_sunburst_treemap.png b/test/image/baselines/uniformtext_sunburst_treemap.png index 48a5679d48e..eb00334ba3e 100644 Binary files a/test/image/baselines/uniformtext_sunburst_treemap.png and b/test/image/baselines/uniformtext_sunburst_treemap.png differ diff --git a/test/image/mocks/sunburst_inside-text-orientation_clock.json b/test/image/mocks/sunburst_inside-text-orientation_clock.json new file mode 100644 index 00000000000..59bd9976ae0 --- /dev/null +++ b/test/image/mocks/sunburst_inside-text-orientation_clock.json @@ -0,0 +1,402 @@ +{ + "data": [ + { + "name": "horizontal", + "insidetextorientation": "horizontal", + "type": "sunburst", + "parents": [ + "", + "A", + "A", + "C", + "C", + "C", + "F", + "F", + "F", + "F", + "J", + "J", + "J", + "J", + "J", + "O", + "O", + "O", + "O", + "O", + "O", + "U", + "U", + "U", + "U", + "U", + "U" + ], + "labels": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ], + "textinfo": "label+value", + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0.5, + 1 + ] + } + }, + { + "name": "radial", + "insidetextorientation": "radial", + "type": "sunburst", + "parents": [ + "", + "A", + "A", + "C", + "C", + "C", + "F", + "F", + "F", + "F", + "J", + "J", + "J", + "J", + "J", + "O", + "O", + "O", + "O", + "O", + "O", + "U", + "U", + "U", + "U", + "U", + "U" + ], + "labels": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ], + "textinfo": "label+value", + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0, + 0.5 + ] + } + }, + { + "name": "tangential", + "insidetextorientation": "tangential", + "type": "sunburst", + "parents": [ + "", + "A", + "A", + "C", + "C", + "C", + "F", + "F", + "F", + "F", + "J", + "J", + "J", + "J", + "J", + "O", + "O", + "O", + "O", + "O", + "O", + "U", + "U", + "U", + "U", + "U", + "U" + ], + "labels": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ], + "textinfo": "label+value", + "domain": { + "x": [ + 0, + 0.5 + ], + "y": [ + 0, + 0.5 + ] + } + }, + { + "name": "auto", + "insidetextorientation": "auto", + "type": "sunburst", + "parents": [ + "", + "A", + "A", + "C", + "C", + "C", + "F", + "F", + "F", + "F", + "J", + "J", + "J", + "J", + "J", + "O", + "O", + "O", + "O", + "O", + "O", + "U", + "U", + "U", + "U", + "U", + "U" + ], + "labels": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z" + ], + "textinfo": "label+value", + "domain": { + "x": [ + 0, + 0.5 + ], + "y": [ + 0.5, + 1 + ] + } + } + ], + "layout": { + "width": 800, + "height": 800, + "margin": { + "t": 10, + "b": 10, + "l": 10, + "r": 10 + }, + "legend": { + "title": { + "text": "inside text orientation" + } + }, + "font": { + "size": 14 + }, + "shapes": [ + { + "type": "rect", + "layer": "below", + "x0": 0, + "x1": 0.5, + "y0": 0, + "y1": 0.5 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.5, + "x1": 1, + "y0": 0, + "y1": 0.5 + }, + { + "type": "rect", + "layer": "below", + "x0": 0.5, + "x1": 1, + "y0": 0.5, + "y1": 1 + }, + { + "type": "rect", + "layer": "below", + "x0": 0, + "x1": 0.5, + "y0": 0.5, + "y1": 1 + } + ], + "annotations": [ + { + "text": "auto", + "showarrow": false, + "xref": "paper", + "yref": "paper", + "xanchor": "right", + "yanchor": "bottom", + "x": 0.5, + "y": 0.5, + "font": { + "size": 20 + } + }, + { + "text": "tangential", + "showarrow": false, + "xref": "paper", + "yref": "paper", + "xanchor": "right", + "yanchor": "bottom", + "x": 0.5, + "y": 0, + "font": { + "size": 20 + } + }, + { + "text": "radial", + "showarrow": false, + "xref": "paper", + "yref": "paper", + "xanchor": "right", + "yanchor": "bottom", + "x": 1, + "y": 0, + "font": { + "size": 20 + } + }, + { + "text": "horizontal", + "showarrow": false, + "xref": "paper", + "yref": "paper", + "xanchor": "right", + "yanchor": "bottom", + "x": 1, + "y": 0.5, + "font": { + "size": 20 + } + } + ] + } +} diff --git a/test/image/mocks/uniformtext_pie_8_radial.json b/test/image/mocks/uniformtext_pie_8_radial.json new file mode 100644 index 00000000000..037c522214e --- /dev/null +++ b/test/image/mocks/uniformtext_pie_8_radial.json @@ -0,0 +1,248 @@ +{ + "data": [ + { + "rotation": -360, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0, + 0.24 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": -360, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.25, + 0.49 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": 180, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0, + 0.24 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": 180, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.25, + 0.49 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": -270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.5, + 0.74 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": -270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.75, + 0.99 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": 270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.5, + 0.74 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": 270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "radial", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.75, + 0.99 + ], + "y": [ + 0.5, + 0.99 + ] + } + } + ], + "layout": { + "width": 800, + "height": 500, + "margin": { + "t": 10, + "b": 10, + "l": 10, + "r": 10 + }, + "legend": { + "orientation": "h", + "title": { + "text": "pie uniform text
with radial orientation
minsize=8" + } + }, + "uniformtext": { + "mode": "hide", + "minsize": 8 + } + } +} diff --git a/test/image/mocks/uniformtext_pie_8_tangential.json b/test/image/mocks/uniformtext_pie_8_tangential.json new file mode 100644 index 00000000000..3490e845771 --- /dev/null +++ b/test/image/mocks/uniformtext_pie_8_tangential.json @@ -0,0 +1,248 @@ +{ + "data": [ + { + "rotation": -360, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0, + 0.24 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": -360, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.25, + 0.49 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": 180, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0, + 0.24 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": 180, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.25, + 0.49 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": -270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.5, + 0.74 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": -270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.75, + 0.99 + ], + "y": [ + 0, + 0.49 + ] + } + }, + { + "rotation": 270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L O N G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.5, + 0.74 + ], + "y": [ + 0.5, + 0.99 + ] + } + }, + { + "rotation": 270, + "values": [ + 7, + 0.9, + 0.1 + ], + "text": [ + "L
O
N
G", + "text", + "invisible" + ], + "type": "pie", + "textinfo": "text", + "insidetextorientation": "tangential", + "textposition": "inside", + "hole": 0.5, + "domain": { + "x": [ + 0.75, + 0.99 + ], + "y": [ + 0.5, + 0.99 + ] + } + } + ], + "layout": { + "width": 800, + "height": 500, + "margin": { + "t": 10, + "b": 10, + "l": 10, + "r": 10 + }, + "legend": { + "orientation": "h", + "title": { + "text": "pie uniform text
with tangential orientation
minsize=8" + } + }, + "uniformtext": { + "mode": "hide", + "minsize": 8 + } + } +}