Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eef3e16

Browse files
committed
handle yanchor for text
1 parent 929bbae commit eef3e16

File tree

1 file changed

+73
-35
lines changed

1 file changed

+73
-35
lines changed

src/components/shapes/draw.js

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe
598598
}
599599

600600
function drawLabel(gd, index, options, shapeGroup) {
601-
if(!options.label) return;
601+
if(!(options.label && options.x0 && options.x1)) return;
602602

603603
// Remove existing label
604604
shapeGroup.selectAll('.shape-label').remove();
@@ -634,32 +634,40 @@ function drawLabel(gd, index, options, shapeGroup) {
634634
var shapey0 = y2p(options.y0);
635635
var shapey1 = y2p(options.y1);
636636

637-
// Calculate correct (x,y) for text
638-
var textPos = calcTextPosition(shapex0, shapey0, shapex1, shapey1, options);
639-
var textx = textPos.textx;
640-
var texty = textPos.texty;
641-
642-
var textangle = options.label.textangle;
643-
644637
// Handle 'auto' angle for lines
638+
var textangle = options.label.textangle;
645639
if(textangle === 'auto') {
646640
textangle = calcTextAngle(shapex0, shapey0, shapex1, shapey1);
647641
}
648642

643+
// Do an initial render just so we can get the bounding box height --
644+
// this is not the final render
645+
labelText.call(function(s) {
646+
s.call(Drawing.font, font).attr({});
647+
svgTextUtils.convertToTspans(s, gd);
648+
return s;
649+
});
650+
var textBB = Drawing.bBox(labelText.node());
651+
652+
// Calculate correct (x,y) for text
653+
// We also determine true xanchor since xanchor depends on position when set to 'auto'
654+
var textPos = calcTextPosition(shapex0, shapey0, shapex1, shapey1, options, textangle, textBB);
655+
var textx = textPos.textx;
656+
var texty = textPos.texty;
657+
var xanchor = textPos.xanchor;
658+
649659
function textLayout(s) {
650-
if(options.x0 && options.y0) {
651-
s.call(Drawing.font, font)
652-
.attr({
653-
'text-anchor': {
654-
left: 'start',
655-
center: 'middle',
656-
right: 'end'
657-
}[options.label.xanchor],
658-
'y': texty,
659-
'x': textx,
660-
'transform': 'rotate(' + textangle + ',' + textx + ',' + texty + ')'
661-
});
662-
}
660+
s.call(Drawing.font, font)
661+
.attr({
662+
'text-anchor': {
663+
left: 'start',
664+
center: 'middle',
665+
right: 'end'
666+
}[xanchor],
667+
'y': texty,
668+
'x': textx,
669+
'transform': 'rotate(' + textangle + ',' + textx + ',' + texty + ')'
670+
});
663671
svgTextUtils.convertToTspans(s, gd);
664672
return s;
665673
}
@@ -678,22 +686,22 @@ function calcTextAngle(shapex0, shapey0, shapex1, shapey1) {
678686
return -180 / Math.PI * Math.atan2(dy, dx);
679687
}
680688

681-
function calcTextPosition(shapex0, shapey0, shapex1, shapey1, shapeOptions) {
689+
function calcTextPosition(shapex0, shapey0, shapex1, shapey1, shapeOptions, actualTextAngle, textBB) {
682690
var textPosition = shapeOptions.label.position;
683691
var textPadding = shapeOptions.label.padding;
684692
var shapeType = shapeOptions.type;
685-
var textAngle = shapeOptions.label.textangle;
693+
var textAngleRad = Math.PI / 180 * actualTextAngle;
694+
var xanchor = shapeOptions.label.xanchor;
695+
var yanchor = shapeOptions.label.yanchor;
686696

687-
var textx, texty;
697+
var textx, texty, paddingX, paddingY;
688698

689699
// Text position functions differently for lines vs. other shapes
690700
if(shapeType === 'line') {
691701
// Handle special case for padding when angle is 'auto' for lines
692702
// Padding should be treated as an orthogonal offset in this case
693703
// Otherwise, padding is just a simple x and y offset
694-
var paddingX, paddingY;
695-
if(textAngle === 'auto') {
696-
var textAngleRad = Math.PI / 180 * calcTextAngle(shapex0, shapey0, shapex1, shapey1);
704+
if(shapeOptions.label.textangle === 'auto') {
697705
paddingX = textPadding * Math.sin(textAngleRad);
698706
paddingY = -textPadding * Math.cos(textAngleRad);
699707
} else {
@@ -702,39 +710,69 @@ function calcTextPosition(shapex0, shapey0, shapex1, shapey1, shapeOptions) {
702710
}
703711

704712
// Handle directional offset for top vs. bottom vs. center of line (default is 'top')
705-
var paddingMultiplier = textPosition.indexOf('middle') !== -1 ? 0 : textPosition.indexOf('bottom') !== -1 ? -1 : 1;
713+
var paddingMultiplier;
714+
if(textPosition.indexOf('middle') !== -1) {
715+
paddingMultiplier = 0;
716+
if(yanchor === 'auto') yanchor = 'middle';
717+
} else if(textPosition.indexOf('bottom') !== -1) {
718+
paddingMultiplier = -1;
719+
if(yanchor === 'auto') yanchor = 'top';
720+
} else {
721+
paddingMultiplier = 1;
722+
if(yanchor === 'auto') yanchor = 'bottom';
723+
}
724+
// var paddingMultiplier = textPosition.indexOf('middle') !== -1 ? 0 : textPosition.indexOf('bottom') !== -1 ? -1 : 1;
706725

707726
if(textPosition.indexOf('start') !== -1) {
708727
textx = shapex0 + paddingX * paddingMultiplier;
709728
texty = shapey0 + paddingY * paddingMultiplier;
729+
if(xanchor === 'auto') xanchor = (shapex1 >= shapex0) ? 'right' : 'left';
710730
} else if(textPosition.indexOf('end') !== -1) {
711731
textx = shapex1 + paddingX * paddingMultiplier;
712732
texty = shapey1 + paddingY * paddingMultiplier;
733+
if(xanchor === 'auto') xanchor = (shapex1 >= shapex0) ? 'left' : 'right';
713734
} else { // Default: center
714735
textx = (shapex0 + shapex1) / 2 + paddingX * paddingMultiplier;
715736
texty = (shapey0 + shapey1) / 2 + paddingY * paddingMultiplier;
737+
if(xanchor === 'auto') xanchor = 'center';
716738
}
717739
} else { // Text position for shapes that are not lines
718740
// calc horizontal position
719-
if(textPosition.indexOf('top') !== -1) {
720-
textx = Math.max(shapex0, shapex1) + textPadding;
721-
} else if(textPosition.indexOf('bottom') !== -1) {
722-
textx = Math.min(shapex0, shapex1) - textPadding;
741+
// Horizontal needs a little extra padding to look balanced
742+
paddingX = textPadding + 3;
743+
if(textPosition.indexOf('right') !== -1) {
744+
textx = Math.max(shapex0, shapex1) + paddingX;
745+
if(xanchor === 'auto') xanchor = 'left';
746+
} else if(textPosition.indexOf('left') !== -1) {
747+
textx = Math.min(shapex0, shapex1) - paddingX;
748+
if(xanchor === 'auto') xanchor = 'right';
723749
} else { // Default: center
724750
textx = (shapex0 + shapex1) / 2;
751+
if(xanchor === 'auto') xanchor = 'center';
725752
}
726753

727754
// calc vertical position
755+
paddingY = textPadding
728756
if(textPosition.indexOf('top') !== -1) {
729-
texty = Math.min(shapey0, shapey1) - textPadding;
757+
texty = Math.min(shapey0, shapey1) - paddingY;
758+
if(yanchor === 'auto') yanchor = 'bottom';
730759
} else if(textPosition.indexOf('bottom') !== -1) {
731-
texty = Math.max(shapey0, shapey1) + textPadding;
760+
texty = Math.max(shapey0, shapey1) + paddingY;
761+
if(yanchor === 'auto') yanchor = 'top';
732762
} else { // Default: middle
733763
texty = (shapey0 + shapey1) / 2;
764+
if(yanchor === 'auto') yanchor = 'middle';
734765
}
735766
}
736767

737-
return { textx: textx, texty: texty };
768+
// Shift vertical (& horizontal) position according to `yanchor`
769+
// This shiftFraction is only a rough approximation, but maybe good enough?
770+
var shiftFraction = {middle: -0.2, bottom: 0.3, top: -0.7}[yanchor];
771+
var textHeight = textBB.height;
772+
var xshift = textHeight * Math.sin(textAngleRad) * shiftFraction;
773+
var yshift = -textHeight * Math.cos(textAngleRad) * shiftFraction;
774+
775+
return { textx: textx + xshift, texty: texty + yshift, xanchor: xanchor };
738776
}
739777

740778
function movePath(pathIn, moveX, moveY) {

0 commit comments

Comments
 (0)