首页 > 解决方案 > 如何从 Canvas 和 JS 中的输入中旋转动态文本?

问题描述

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

图像
(来源:hostpic.xyz

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

图像

您可以在下面的 JSFiddle 链接上找到代码,您可以在其中输入文本,并且在 JSFiddle 示例中应将其写为“品牌”字样。

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

标签: javascriptcanvasrotationdynamic-text

解决方案


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

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

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

另一个有用的功能是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>


通过这种概念验证工作,一个问题是在画布上缩放图像会导致视觉伪影。这个问题可以通过JS或者通过缩小源图片本身来解决,但是此时最好将图片作为一个元素来规避整个问题。

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

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

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>


推荐阅读