如何从 Canvas 和 JS 中的输入旋转动态文本?

How to rotate dynamic text from input in Canvas and JS?

我正在使用 Canvas 和 Javascript 进行一个框样式项目,但我无法按我想要的方式旋转文本(从下到上书写)。


(来源:hostpic.xyz

我遵循了教程 (https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/) 并尝试在我的代码中对其进行调整,但我做不到。

您可以在下面的 JSFiddle link 上找到代码,您可以在其中输入文本,在 JSFiddle 示例中应将其写为 "brand" 单词。

https://jsfiddle.net/ParkerIndustries/mgne9x5u/5/

一切都在 init() 函数中:

function init() {
    var elem = document.getElementById('elem');
    var circle_canvas = document.createElement("canvas");
    var context = circle_canvas.getContext("2d");
    var img = new Image();
    img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
    context.drawImage(img, 0, 0, 500, 650);
    circle_canvas.width = 500;
    circle_canvas.height = 650;
    context.fillStyle = "#000000";
    //context.textAlign = 'center';
    var UserInput = document.getElementById("UserInput");
    context.save();
    context.translate( circle_canvas.width - 1, 0 );
    UserInput.oninput = function() {
        context.clearRect(0, 0, 500, 650);
        context.drawImage(img, 0, 0, 500, 650);
        var text = UserInput.value;
        console.log(text);
        if (text.length < 12) {
            context.rotate(3*Math.PI/2);
            console.log("-12");
            context.font = "50px Righteous";
            context.fillText(text, -350, -170);
            context.restore();
        } else {
            context.rotate(3*Math.PI/2);
            context.font = "25px Righteous";
            context.fillText(text, -350, -170);
            context.restore();
        }
    }
    elem.appendChild(circle_canvas);
}

init();

我在 context.rotate() 函数中尝试了很多值,但无论如何我的文本都是颠倒的。


(来源:hostpic.xyz

你离这里很近了。我建议执行 canvas 平移到屏幕中间 (width / 2, height / 2) 然后旋转 270 度:

context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(270 * Math.PI / 180);

除此之外,我建议进行一轮代码清理以避免不一致的变量名和硬编码数字(尝试使所有内容与 img.widthimg.height 成正比,然后避免文字值。这使得它更容易动态调整您的代码,而无需重新键入所有值。您可以在 img.onload 函数触发后访问 img.widthimg.height

另一个有用的函数是 context.measureText(text),它可以更简单地按比例缩放文本大小。

完整示例:

function init() {
  var userInput = document.getElementById("user-input");
  var elem = document.getElementById("elem");
  var canvas = document.createElement("canvas");
  var context = canvas.getContext("2d");
  var img = new Image();
  
  img.onload = function () {
    canvas.width = img.width / 3;
    canvas.height = img.height / 3;
    context.drawImage(img, 0, 0, canvas.width, canvas.height);
    context.fillStyle = "#000000";
    context.textAlign = "center";
    elem.appendChild(canvas);
    
    userInput.oninput = function () {
      var text = userInput.value;
      var textSizePx = 50 - context.measureText(text).width / 10;
      context.font = textSizePx + "px Righteous";
      context.clearRect(0, 0, canvas.width, canvas.height);
      context.drawImage(img, 0, 0, canvas.width, canvas.height);
      context.save();
      context.translate(canvas.width / 2, canvas.height / 2);
      context.rotate(270 * Math.PI / 180);
      context.fillText(text, 0, -canvas.width / 20);
      context.restore();
    }
  };
    
  img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
}

init();
<div id="elem">
  <input type="text" id="user-input" maxlength="15">
</div>


随着概念验证工作的进行,一个问题是在 canvas 上缩放图像会导致视觉伪影。这个问题可以通过with JS或者通过缩小源图像本身来解决,但是在这一点上,最好将图像作为一个元素来规避整个问题。

同样,也没有明显的理由在 canvas 上呈现文本;我们也可以为此制作一个元素。将文本移动到 HTML/CSS 可以更有效地改变它的外观(我在这里没有做太多样式,所以这是一个练习,可以让它更自然地融入图像)。

这是一个没有 canvas 的重写,看起来更干净并且应该更易于维护:

function init() {
  var userInput = document.querySelector("#user-input");
  var img = document.querySelector("#product-img");
  var imgRect = img.getBoundingClientRect();  
  var overlayText = document.querySelector("#overlay-text");
  var overlay = document.querySelector("#overlay");
  overlay.style.width = (imgRect.width * 0.86) + "px";
  overlay.style.height = imgRect.height + "px";

  userInput.addEventListener("input", function () {
    overlayText.innerText = userInput.value;
    overlayText.style.fontSize = (50 - userInput.value.length * 2) + "px";
  });
}

init();
#product-img {
  position: absolute;
}

#overlay {
  position: absolute;
  display: flex;
}

#overlay-text {
  font-family: Verdana, sans-serif;
  color: #333;
  transform: rotate(270deg);
  margin: auto;
  cursor: default;
}
<div>
  <input type="text" id="user-input" maxlength="15">
</div>
<div id="product-container">
  <img id="product-img" src="https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg" width=666 height=500 />
  <div id="overlay">
    <div id="overlay-text"></div>
  </div>
</div>