0

I want to add a text to the center of quadratic curve or line like this:

text on curve

I tried to add a text with ctx.fillText but it overlaps the curve. text on curve but it overlaps

how can I draw a curve where the curve does not go over the text?

My code:

// draw the curve
const startPoints = this._getStartPoints(); // returns start points [x, y]
const endPoints = this._getEndPoints(); // returns end points [x, y]

ctx.moveTo(...startPoints);

ctx.quadraticCurveTo(...this.getControlPoints(), ...endPoints);
ctx.stroke();

// draw the text
const textMeasurement = ctx.measureText('text on curve');
const middlePoints = this._getControlPoints(); // returns the middle point of the curve [x, y]
const textXPoint = middlePoints[0] - textMeasurement.width / 2;
ctx.fillText('text on curve', textXPoint, middlePoints[1]);
mediumgoal
  • 11
  • 1
  • 2
    Draw a curve. Draw a rectangle in the background colour where the text will go. Then draw the text. – Thomas Jan 03 '23 at 10:39
  • If the background is not single colored you have to split your curve in two parts. Draw part 1, leave space for the text and then draw part 2. This might not be easy to achieve tough. – cloned Jan 03 '23 at 10:44
  • @Thomas But the bounding box of the rectangle may affect any shape when the line and that shape are colliding. – mediumgoal Jan 03 '23 at 12:46
  • @cloned Yes... seems hard to solve with that way. – mediumgoal Jan 03 '23 at 12:47

1 Answers1

0

Clipping

Use ctx.clip to prevent drawing on parts of the canvas.

In this case you want to draw only outside a bounding area. To do this create two clipping rectangle. The first bounding the whole canvas, the second bounding the text bounding area.

Then clip using the "evenodd" winding (fill) rule.

Example code

Example of clipping outside a bounding box using two rectangle as described above.

const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const someText = {
    str: "Clip outside...",
    x: w / 2,
    y: h / 2,
    style: {    
        font: "24px arial",
        textAlign: "center",
        textBaseline: "middle",
    }
};

//-------------------------------------------------------------
// Draw text and get text bounding rect
drawText(someText);
const tBWidth = ctx.measureText(someText.str).width;
const textBounds = {
    x: someText.x - tBWidth * 0.6,
    y: someText.y - 15,
    w: tBWidth * 1.2,
    h: 30,
};

//-------------------------------------------------------------
// Clip and draw lines
ctx.save(); // must have to turn off clip

clipOutside(textBounds);

// Draw some lines outside clip bounds 
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(-10, -10);
ctx.lineTo(w + 10, h + 10);
ctx.moveTo(w, 0);
ctx.quadraticCurveTo(w * 0.5, h * 0.8, 0, h * 0.3);
ctx.stroke();

ctx.restore(); // Removes the clip

// all done...................
//-------------------------------------------------------------

function drawText(textObj) {
    Object.assign(ctx, textObj.style);
    ctx.fillText(textObj.str, textObj.x, textObj.y);
}
function clipOutside(rect) {
    ctx.beginPath();
    ctx.rect(-1, -1, w + 2, h + 2);
    ctx.rect(rect.x, rect.y, rect.w, rect.h);
    ctx.clip("evenodd");
}
canvas {
   border: 1px solid black;
}
<canvas id="canvas" height="160" width="400"></canvas>
Blindman67
  • 51,134
  • 11
  • 73
  • 136