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

泄露秘密 提交于 2019-12-11 05:22:38

问题


I'm working on a box styling project with Canvas and Javascript, and I can't rotate the text the way I want (written from bottom to the top).


(source: hostpic.xyz)

I followed a tutorial (https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/) and tried to adapt it in my code, but I couldn't make it.

You can find the code on the JSFiddle link below, there's an input where you can type your text and it should be written as the "brand" word in the JSFiddle example.

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

Everything is in the init() function:

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();

I tried a lot a values in the context.rotate() function but in any way my text is upside down.


(source: hostpic.xyz)


回答1:


You're pretty close here. I suggest performing the canvas translation to the middle of the screen (width / 2, height / 2) and then rotating by 270 degrees:

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

Beyond that, I recommend a round of code cleanup to avoid inconsistent variable names and hardcoded numbers (try to make everything proportional to img.width and img.height, then avoid literal values. This makes it easier to adjust your code dynamically without having to re-type all of the values. You can access img.width and img.height after the img.onload function fires.

Another useful function is context.measureText(text), which makes it simpler to proportionally scale text size.

Full example:

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>

With that proof-of-concept working, one problem is that scaling the image on canvas causes visual artifacts. This problem can be overcome with JS or by scaling down the source image itself, but at this point, it's best to make the image as an element and circumvent the entire problem.

Similarly, there's no obvious reason to render text on canvas either; we can make an element for this as well. Moving text to HTML/CSS gives more power over how it looks (I didn't do much with style here, so it's an exercise to make it blend more naturally into the image).

Here's a rewrite without canvas that looks much cleaner and should be more maintainable:

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>


来源:https://stackoverflow.com/questions/57630343/how-to-rotate-dynamic-text-from-input-in-canvas-and-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!