如何更改出现在 arc - context 2d 上的文本顺序,并停止 canvas 2d 上的填充样式覆盖(与 chart.js 一起使用)?

How to change order of text to appear on arc - context 2d, and stop fill style overwriting on the canvas 2d (using with chart.js)?

所以我试图在上下文 2d 中构建一个带有文本的圆弧作为圆角矩形,但是文本在它下面并且被隐藏了,另外,圆弧的填充样式被文本。这是我得到的和我想要的:

这是带有代码的 js fiddle:https://jsfiddle.net/abhishek_soni/vzs6dLy9/19/

这是相同的代码:

Html代码:

<canvas></canvas>

Js代码:

var roundRect = function(ctx, x, y, w, h, r) {
  var x2 = x + w;
  var y2 = y + h;

  if (w < 2 * r) r = w / 2;
  if (h < 2 * r) r = h / 2;

  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x2, y, x2, y2, r);
  ctx.arcTo(x2, y2, x, y2, r);
  ctx.arcTo(x, y2, x, y, r);
  ctx.arcTo(x, y, x2, y, r);
};

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');

context.save();
roundRect(context, 0, 0, 50, 60, 20);
context.fillStyle = 'red'; // This should work, but it doesn't 
context.fill();
context.restore();

context.fillStyle = 'green';
context.fillText('Hey', 50, 80) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();

context.save();
roundRect(context, 100, 100, 50, 90, 20);
context.fillStyle = 'red'; // This should work, but it doesn't 
context.fill();
context.restore();

context.fillStyle = 'green';
context.fillText('Hey', 90, 100) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();

context.save();
roundRect(context, 300, 100, 50, 120, 20);
context.fillStyle = 'red'; // This should work, but it doesn't 
context.fill();
context.restore();

context.fillStyle = 'green';
context.fillText('Hey', 90, 130) // if I change this to 50 it hides behind the arc, which I don't want.
context.textAlign = "center";
context.fill();

问题是您在创建不需要的文本后调用 fill()fill() 应用于之前绘制的形状。 fillText()fillRect() 等方法的目的是让您无需在之后调用 fill() 即可进行绘制。

不要在文本后调用 fill 并且它有效。

接下来要将文本对齐到形状的中心,我会计算中心并将文本放置在那里,然后使用 context.textAlign = 'center'; 将其居中。

这是一个例子

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;

let center = {}
var roundRect = function(ctx, x, y, w, h, r) {
  var x2 = x + w;
  var y2 = y + h;
  center = {x: x + w/2, y: y + h/2}
  
  if (w < 2 * r) r = w / 2;
  if (h < 2 * r) r = h / 2;

  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x2, y, x2, y2, r);
  ctx.arcTo(x2, y2, x, y2, r);
  ctx.arcTo(x, y2, x, y, r);
  ctx.arcTo(x, y, x2, y, r);
  ctx.closePath();
};



context.fillStyle = 'red';
roundRect(context, 0, 0, 50, 60, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";

context.fillStyle = 'red';
roundRect(context, 100, 100, 50, 90, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y)
context.textAlign = "center";

context.fillStyle = 'red';
roundRect(context, 300, 100, 50, 120, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";
<canvas id="canvas"></canvas>

我还将添加一个使用 class 的示例来执行此操作。与其他方法相比,我更喜欢这种方法。如果你不需要不同的颜色形状,你可以去掉 color 参数。如果您想要不同颜色的文本,您可以为此添加一个。

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;

class roundRect {
  constructor(x, y, w, h, r, c) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.x2 = this.x + this.w;
    this.y2 = this.y + this.h;
    this.center = { x: x + w / 2, y: y + h / 2 };
    this.r = r;
    this.color = c;
  }
  drawShape() {
    if (this.w < 2 * this.r) this.r = this.w / 2;
    if (this.h < 2 * this.r) this.r = this.h / 2;
    
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.moveTo(this.x + this.r, this.y);
    ctx.arcTo(this.x2, this.y, this.x2, this.y2, this.r);
    ctx.arcTo(this.x2, this.y2, this.x, this.y2, this.r);
    ctx.arcTo(this.x, this.y2, this.x, this.y, this.r);
    ctx.arcTo(this.x, this.y, this.x2, this.y, this.r);
    ctx.closePath();
    ctx.fill();
  }
  drawText() {
    ctx.fillStyle = 'green';
    ctx.textAlign = "center";
    ctx.textBaseline = 'middle';
    ctx.fillText("Hey", this.center.x, this.center.y); 
  }
}

let rect1 = new roundRect(0, 0, 50, 60, 20, 'red', 'Text')
let rect2 = new roundRect(60, 0, 50, 80, 20, 'lightblue', 'Text')
let rect3 = new roundRect(120, 0, 50, 100, 20, 'lightgreen', 'Text')

rect1.drawShape();
rect1.drawText();
rect2.drawShape();
rect2.drawText();
rect3.drawShape();
rect3.drawText();
<canvas id="canvas"></canvas>

编辑:

要旋转您的文本,请使用以下方法。

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;

let center = {}
var roundRect = function(ctx, x, y, w, h, r) {
  var x2 = x + w;
  var y2 = y + h;
  center = {x: x + w/2, y: y + h/2}
  
  if (w < 2 * r) r = w / 2;
  if (h < 2 * r) r = h / 2;

  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x2, y, x2, y2, r);
  ctx.arcTo(x2, y2, x, y2, r);
  ctx.arcTo(x, y2, x, y, r);
  ctx.arcTo(x, y, x2, y, r);
  ctx.closePath();
};



context.fillStyle = 'red';
roundRect(context, 0, 0, 50, 60, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";

context.fillStyle = 'red';
roundRect(context, 100, 100, 50, 90, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.save() //save before you transform something
context.translate(center.x, center.y) //use this to position
context.rotate(degToRad(90)) //rotate here using degrees
context.fillText('Hey', 0, 0) //draw this a (0, 0)
context.fillStyle = 'lightblue'; //delete this
context.fillRect(0, 0, canvas.width, canvas.height) //and this
context.restore() //restore when done with all objects you want affected
context.textAlign = "center";


context.fillStyle = 'red';
roundRect(context, 300, 100, 50, 120, 20);
context.fill();

context.fillStyle = 'green';
context.textAlign = 'center';
context.fillText('Hey', center.x, center.y);
context.textAlign = "center";

function degToRad(deg) {
  return deg * (Math.PI/180)
}
<canvas id="canvas"></canvas>