0

I'm trying to add text (TextPath) inside an Arc shape, that is following the curve of en Arc. Making a curved TextPath is easy, however I'm failing to put it on top on Arc shape.

If I set x and y of both objects to for.ex. 100 and 100, they end up in illogical locations, so I'm obviously failing to understand something here. What I'm trying to achieve is shown in attached screenshot - could someone make demo of putting a TextPath on top of en Arc ? Thanks.

what I'm trying to achieve

Lauris
  • 13
  • 2
  • Can you show what did you try? – lavrton Oct 31 '19 at 00:39
  • I think I messed up SVG path, which moved TextPath somewhere I was not expecting it. I made a demo, https://jsbin.com/rayapavila/edit?html,js,output – Lauris Oct 31 '19 at 14:15
  • Demo has couple problems - TextPath is placed on ARC by trial and error with hardcoded values, not like "here is an ARC, put text on it". Second, text is facing out of en ARC, while I'd like it to face inside of en ARC. Could you edit my demo and make a proper example of putting TextPath on an ARC ? I think it would be useful to many konvajs users. Thanks – Lauris Oct 31 '19 at 14:23

1 Answers1

2

I slightly modified your demo to remove hardcoded values as much as possible.

You just need to correctly generate an SVG path. You can use some answers from here: How to calculate the SVG Path for an arc (of a circle)

Also, you can use Konva.Path shape to debug the generated path.

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

function describeArc(x, y, radius, startAngle, endAngle){

    var endAngleOriginal = endAngle;
    if(endAngleOriginal - startAngle === 360){
        endAngle = 359;
    }

    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);

    var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";

    if(endAngleOriginal - startAngle === 360){
        var d = [
              "M", start.x, start.y, 
              "A", radius, radius, 0, arcSweep, 0, end.x, end.y, "z"
        ].join(" ");
    }
    else{
      var d = [
          "M", start.x, start.y, 
          "A", radius, radius, 0, arcSweep, 0, end.x, end.y
      ].join(" ");
    }

    return d;       
}



var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height
});

var layer = new Konva.Layer();
stage.add(layer);

var arc = new Konva.Arc({
  x: 250,
  y: 250,
  innerRadius: 100,
  outerRadius: 170,
  angle: 260,
  rotation: 0,
  draggable: true,
  fill: 'yellow',
  stroke: 'black',
  strokeWidth: 4,
  offset: 0,
});

layer.add(arc);

var tr1 = new Konva.Transformer({
  node: arc,
  resizeEnabled: false

});

layer.add(tr1);

var txt = new Konva.TextPath({
  x: arc.x(),
  y: arc.y(),
  draggable: true,
  fill: '#333',
  fontSize: 22,
  fontFamily: 'Arial',
  text: "Hello world !",
  align: 'center',
  data: describeArc(0, 0, (arc.innerRadius() + arc.outerRadius()) / 2, 90, 90 + arc.getAttr("angle")),
});

layer.add(txt);

var tr2 = new Konva.Transformer({
  node: txt,
  resizeEnabled: false,
});
layer.add(tr2);


const path = new Konva.Path({
  x: txt.x(),
  y: txt.y(),
  data: txt.data(),
  stroke: 'red'
});
layer.add(path);

layer.draw();

Demo: https://jsbin.com/muwobaxipe/3/edit?js,output

lavrton
  • 18,973
  • 4
  • 30
  • 63
  • Appreciate this answer, very useful! Is there a way to flip the text? I have a circle and want to run the text across the top however it appears upside down as the text faces towards the outside of the arc. – ubiQ Oct 23 '20 at 18:51