问题
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