Skip to content

Commit d66de64

Browse files
committed
Title cutoff on y-axis or overlaps with tick label
Address the following issues where the title overlapped the y-axis tick labels or a portion of the title was cutoff plotly#1504 plotly#296 Might also address: plotly#1594
1 parent 679c0d3 commit d66de64

File tree

1 file changed

+107
-4
lines changed

1 file changed

+107
-4
lines changed

src/plots/plots.js

+107-4
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,38 @@ plots.autoMargin = function(gd, id, o) {
14331433
}
14341434
};
14351435

1436+
plots.calculateTextMeasurements = function(text, font, angle, axisName) {
1437+
if(typeof(font) !== "string"){
1438+
font = font.size + "px "+ font.family;
1439+
}
1440+
1441+
var tag = document.createElement("div");
1442+
tag.style.position = "absolute";
1443+
tag.style.left = "-999em";
1444+
tag.style.whiteSpace = "nowrap";
1445+
tag.style.font = font;
1446+
tag.innerHTML = text;
1447+
1448+
1449+
if(angle == 'auto' && axisName == 'x'){
1450+
angle = 90
1451+
}
1452+
1453+
if(!isNaN(+angle)){
1454+
tag.style.transform = 'rotate('+ angle+'deg)';
1455+
}
1456+
1457+
document.body.appendChild(tag);
1458+
var rec = tag.getBoundingClientRect();
1459+
1460+
var width = rec.width;
1461+
var height = rec.height;
1462+
1463+
document.body.removeChild(tag);
1464+
1465+
return {width: width, height: height};
1466+
}
1467+
14361468
plots.doAutoMargin = function(gd) {
14371469
var fullLayout = gd._fullLayout;
14381470
if(!fullLayout._size) fullLayout._size = {};
@@ -1441,13 +1473,84 @@ plots.doAutoMargin = function(gd) {
14411473
var gs = fullLayout._size,
14421474
oldmargins = JSON.stringify(gs);
14431475

1476+
//Lets adjust the layout margin to account for the axis tick label positions to prevent overflow issues and overlapping of labels
1477+
var adjustLeftMargin = [], adjustRightMargin = [] , adjustTopMargin = [], adjustBottomMargin = [];
1478+
var layers = ['yaxis', 'xaxis', 'xaxis2']//these are the only layers I want to adjust the layout margin
1479+
var axes = Plotly.Axes;
1480+
var measurementKeys = {'left': 'width', 'right': 'width', 'top': 'height','bottom': 'height'};
1481+
1482+
layers.forEach(function(layerName) {
1483+
var axisLayer = fullLayout[layerName];
1484+
if(axisLayer && axisLayer._length){
1485+
var axisRange = axes.calcTicks(axisLayer);
1486+
var largestVal = {text:''}
1487+
var axisName = axisLayer._id.charAt(0);
1488+
1489+
//find the largest label. this can be optimize.. but considering that the data is small; I'm not going to worry about it
1490+
for(var i=0; i<axisRange.length; i++ ){
1491+
if(axisRange[i].text.length >= largestVal.text.length){
1492+
largestVal = axisRange[i];
1493+
}
1494+
}
1495+
1496+
var measurement = plots.calculateTextMeasurements(largestVal.text, axisLayer.tickfont, axisLayer.tickangle, axisName);
1497+
//separate for readablity
1498+
var key = measurementKeys[axisLayer.side || (axisName =='x'? 'bottom': 'left')];
1499+
var adjustedMargin = measurement[key];
1500+
//Ideally we should calculate the title's deminsion base on its angle.. but I dont know where that info is stored.. so lets use the axis name to determine its angle
1501+
var angle = (axisName == 'y'? 90: 0);
1502+
measurement = plots.calculateTextMeasurements(axisLayer.title, axisLayer.titlefont, angle);
1503+
if(axisName == 'y'){
1504+
//Most likely the text will be rotated 90degees on the Y-axis.. in that case we care about the width of the text.
1505+
//So the width of the title + the largest tick's width would give us the adjusted margin
1506+
adjustedMargin += measurement.width;
1507+
} else {
1508+
//rotated height of tick + height of title
1509+
adjustedMargin += measurement.height;
1510+
}
1511+
1512+
switch(axisLayer.side){
1513+
case 'left':
1514+
adjustLeftMargin.push(adjustedMargin);
1515+
break;
1516+
case 'right':
1517+
adjustRightMargin.push(adjustedMargin);
1518+
break;
1519+
case 'top':
1520+
adjustTopMargin.push(adjustedMargin);
1521+
break;
1522+
case 'bottom':
1523+
adjustBottomMargin.push(adjustedMargin);
1524+
break;
1525+
}
1526+
}
1527+
});
1528+
1529+
if(!adjustLeftMargin.length){
1530+
adjustLeftMargin.push(fullLayout.margin.l || 0);
1531+
}
1532+
if(!adjustRightMargin.length){
1533+
adjustRightMargin.push(fullLayout.margin.r || 0);
1534+
}
1535+
if(!adjustTopMargin.length){
1536+
adjustTopMargin.push(fullLayout.margin.t || 0);
1537+
}
1538+
if(!adjustBottomMargin.length){
1539+
adjustBottomMargin.push(fullLayout.margin.b || 0);
1540+
}
1541+
1542+
adjustLeftMargin.push(0);
1543+
adjustRightMargin.push(0);
1544+
adjustTopMargin.push(0);
1545+
adjustBottomMargin.push(0);
1546+
14441547
// adjust margins for outside components
14451548
// fullLayout.margin is the requested margin,
14461549
// fullLayout._size has margins and plotsize after adjustment
1447-
var ml = Math.max(fullLayout.margin.l || 0, 0),
1448-
mr = Math.max(fullLayout.margin.r || 0, 0),
1449-
mt = Math.max(fullLayout.margin.t || 0, 0),
1450-
mb = Math.max(fullLayout.margin.b || 0, 0),
1550+
var ml = Math.max.apply(null, adjustLeftMargin),
1551+
mr = Math.max.apply(null, adjustRightMargin),
1552+
mt = Math.max.apply(null, adjustTopMargin),
1553+
mb = Math.max.apply(null, adjustBottomMargin),
14511554
pm = fullLayout._pushmargin;
14521555

14531556
if(fullLayout.margin.autoexpand !== false) {

0 commit comments

Comments
 (0)