javascript - 如何通过带有文本换行的多个文本字段在 Canvas 上显示用户输入

标签 javascript html canvas

我正在尝试设置此网站,用户输入的文本会将文本绘制到正在显示的图像的对话气泡中。我有三个问题:

  1. 用户可以向 Canvas 输入文本,但当用户删除字符时, Canvas 上绘制的文本不会更新

  2. 文本根本不会随着用户输入而换行,但当我直接插入字符串时它会换行。我希望文本与用户输入一起换行

  3. 每当用户开始在新的输入框中键入内容时, Canvas 中的所有文本都会被删除。

我在这里寻找了在线教程和答案,但它们都不是我在这里正常工作所需的确切解决方案。任何其他建议都会有帮助。

谢谢!

<html>
<input id="input-text" type="text" onkeyup="usertextChange(this.value)" 
maxlength="6" />
<input id="input-text2" type="text" onkeyup="usertextChange2(this.value)" 
maxlength="5" />
<input id="input-text3" type="text" onkeyup="usertextChange3(this.value)" 
maxlength="12" />
<input id="input-text4" type="text" onkeyup="usertextChange4(this.value)" 
maxlength="18" />
<div class="art-container">
<canvas id="canvas" width="576" height="576">
Canvas requires a browser that supports HTML5.

</canvas>
<img crossOrigin="Anonymous"  id="no-crying" 
src="https://cdn.glitch.com/4ed5f9d8-97ad-4c53-b855-3e8d508ba2f3%2FDVSN- 
FUTURE-NO-CRYIN-FINAL-NoText.jpg?v=1572122142300"/>

</div>
</html>

<style>
#input-text, #input-text2, #input-text3, #input-text4 {
width: 90%;
font-size: 18px;
height: 24px;
text-transform: uppercase;
padding: 0 8px;
background-color: transparent;
color: red;
border: 2px solid black;
outline: none;
border-radius: 4px;
margin-bottom: 12px;
margin-left: auto;
margin-right: auto;
font-weight: 500;
font-family: bubblegum;
}
#no-crying {
display: none;
}
</style>

<script>

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var maxWidth = 90;
var lineHeight = 45;
var x = 35;
var y = 315;
var text = document.getElementById('input-text1').value;
var text2 = document.getElementById('input-text2').value;
var text3 = document.getElementById('input-text3').value;
var text4 = document.getElementById('input-text4').value;

function drawImage(text) {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var img = document.getElementById('no-crying');  
context.drawImage(img, 0, 0, canvas.width, canvas.height);
}


function wrapText(context, text, x, y, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '';

for(var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
    var metrics = context.measureText(testLine);
    var testWidth = metrics.width;
      if (testWidth > maxWidth && n > 0) {
        context.fillText(line, x, y);
        line = words[n] + ' ';
        y += lineHeight;
      }
      else {
        line = testLine;
      }
    }
    context.fillText(line, x, y);
  }



  window.onload = function() {
    drawImage();
  }

  // USER IMPUT FUNCTIONS
        window.usertextChange = function(val){
    context.clearRect(0, 0, canvas.width, canvas.height);
          context.restore();
    drawImage();
    context.font = '26px Bubblegum';
    context.fillStyle = "#000000";
    context.fillText(val, 39, 315);
    context.save();
    wrapText(context, text, x, y, maxWidth, lineHeight);
        } 
  window.usertextChange2 = function(val){
          context.restore();
    context.font = '22px Bubblegum';
    context.fillStyle = "#000000";
    context.fillText(val, 45, 370);
    context.save();
    wrapText(context, text, x, y, maxWidth, lineHeight);
        } 
  window.usertextChange3 = function(val){
          context.restore();
    context.font = '26px Bubblegum';
    context.fillStyle = "#000000";
    context.fillText(val, 25, 420);
    context.save();
    wrapText(context, text, x, y, maxWidth, lineHeight);
        } 
  window.usertextChange4 = function(val){
    context.restore();
            context.font = '24px Bubblegum';
    context.fillStyle = "#000000";
    context.fillText(val, 48, 360);
    wrapText(context, text, x, y, maxWidth, lineHeight);
        } 


</script>

编辑 我还希望在添加用户输入文本后下载图像。最好的实现方式是什么。这是我根据最近的回复得出的结论

function init() {
text1 = '';
text2 = '';
text3 = '';
text4 = '';
backgroundImg = new Image();
backgroundImg.src = 'https://cdn.glitch.com/4ed5f9d8-97ad-4c53-b855- 
3e8d508ba2f3%2FDVSN-FUTURE-NO-CRYIN-FINAL-NoText.jpg?v=1572122142300';

backgroundImg.setAttribute('crossOrigin', 'anonymous');

function addLink() {
var link = document.createElement('a');
link.innerHTML = 'Download!';
link.addEventListener('click', function(e) {
link.href = canvas.toDataURL();
link.download = "salt-bae.png";
}, false); 
link.className = "instruction";
document.getElementById('input-container').appendChild(link);
}

window.onload = function() {
    drawImage();
    addLink();
}

最佳答案

一些评论:

您使用var text = document.getElementById('input-text1').value; id 为 input-text1,而在 HTML 中,您的 id 为 input-text

您定义函数drawImage(text)text从未使用过的参数。在此函数中,您创建 canvas和一个 context再次出现变量。

您在 DOM 中插入一个隐藏的图像,以便稍后在 Canvas 上绘制它。我认为创建一个新的 Image 更容易对象。

函数wrapText()有点暧昧。它格式化文本吗?它显示什么吗?您可以将其重命名为 displayWrapText()getWrappedText() .

然后,关于您的问题:

  1. 当用户删除字符时,文本不会更新,因为除了输入 #1 之外,当用户键入时,它不会清除气泡,而是会在前一个文本上绘制新文本(它正在获取)较暗)。这就是为什么你看不出有什么区别。删除适用于第一个输入,因为您清除了气泡并再次绘制全文。

  2. Tbh,当我尝试时我忘记了这个问题,现在它运行良好......无论如何,请提供适当的 maxWidthwrapText()功能:有小气泡和大气泡。但是,如果字符串不包含任何空格,则不会换行。

  3. 当用户输入第一个输入时,它会清除 Canvas ,但仅在第一个气泡内再次显示文本,因此其他气泡显示为空。您需要清除 Canvas 并重新绘制所有相应气泡中的文本。

我所做的是应用我之前告诉你的内容,并改进事件处理(请参阅 bubbling ),因为每个输入的代码几乎相同。为了能够在每次更新后重新绘制所有气泡,我在每次更新时存储它们的值。

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const lineHeight = 30;
let backgroundImg;
let text1;
let text2;
let text3;
let text4;

init();

function init() {
  text1 = '';
  text2 = '';
  text3 = '';
  text4 = '';
  backgroundImg = new Image();
  backgroundImg.src = 'https://cdn.glitch.com/4ed5f9d8-97ad-4c53-b855-3e8d508ba2f3%2FDVSN-FUTURE-NO-CRYIN-FINAL-NoText.jpg?v=1572122142300';

  context.drawImage(backgroundImg, 0, 0, canvas.width, canvas.height);

  document.querySelector('#input-container').addEventListener('keyup', function(e) {
    const num = parseInt(e.target.getAttribute('data-bubble'), 10);
    const text = e.target.value;
    saveText(num, text);
    draw(canvas, context, backgroundImg);
  }, false);
}

function draw(canvas, context, backgroundImg) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.drawImage(backgroundImg, 0, 0, canvas.width, canvas.height);
  drawBubble(canvas, context, getTextFrom(1), 39, 315, '26px Bubblegum', '#000000', 110, lineHeight); // bubble 1
	drawBubble(canvas, context, getTextFrom(2), 45, 370, '22px Bubblegum', '#000000', 70, lineHeight); // bubble 2
	drawBubble(canvas, context, getTextFrom(3), 20, 425, '26px Bubblegum', '#000000', 120, lineHeight); // bubble 3
	drawBubble(canvas, context, getTextFrom(4), 20, 515, '24px Bubblegum', '#000000', 120, lineHeight); // bubble 4
}

function getTextFrom(num) {
	switch(num) {
  	case 1: return text1;
  	case 2: return text2;
  	case 3: return text3;
  	case 4: return text4;
    default: '';
  }
}

function saveText(num, text) {
	switch(num) {
  	case 1: text1 = text; break;
  	case 2: text2 = text; break;
  	case 3: text3 = text; break;
  	case 4: text4 = text; break;
  }
}

function displayWrappedText(context, text, x, y, maxWidth, lineHeight) {
  var words = text.split(' ');
  var line = '';

  for (var n = 0; n < words.length; n++) {
    var testLine = line + words[n] + ' ';
    var metrics = context.measureText(testLine);
    var testWidth = metrics.width;
    if (testWidth > maxWidth && n > 0) {
      context.fillText(line, x, y);
      line = words[n] + ' ';
      y += lineHeight;
    } else {
      line = testLine;
    }
  }
  context.fillText(line, x, y);
}

function drawBubble(canvas, context, text, x, y, font, color, maxWidth, lineHeight) {
  context.font = font;
  context.fillStyle = color;
  //context.fillText(text, x, y);
  displayWrappedText(context, text, x, y, maxWidth, lineHeight);
}
#input-container > input {
  width: 90%;
  font-size: 18px;
  height: 24px;
  text-transform: uppercase;
  padding: 0 8px;
  background-color: transparent;
  color: red;
  border: 2px solid black;
  outline: none;
  border-radius: 4px;
  margin-bottom: 12px;
  margin-left: auto;
  margin-right: auto;
  font-weight: 500;
  font-family: bubblegum;
}
<div id="input-container">
  <input class="js-input-text" data-bubble="1" type="text" maxlength="6" />
  <input class="js-input-text" data-bubble="2" type="text" maxlength="5" />
  <input class="js-input-text" data-bubble="3" type="text" maxlength="12" />
  <input class="js-input-text" data-bubble="4" type="text" maxlength="18" />
</div>
<div class="art-container">
  <canvas id="canvas" width="576" height="576">
    Canvas requires a browser that supports HTML5.
  </canvas>
</div>

关于javascript - 如何通过带有文本换行的多个文本字段在 Canvas 上显示用户输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58584613/

相关文章:

javascript - vue-router:防止参数更改时的路由

javascript - 如何在ajax获取函数(msg)中追加子项?

javascript - 在 Canvas 中对齐 Angular 徒手画笔/铅笔工具

javascript - 如何处理智能手机浏览器上的触摸 - javascript

javascript - 我的 useEffect 正在到达调用堆栈,并且在文本更改后,我不知道为什么?

javascript - 为什么我不能为 Material-UI 中禁用的元素自定义类?

javascript - 如何将 application/x-mpegURL 放入 videojs 的源中

php - 我正在尝试使用 $_GET 更改 css 属性,但没有得到结果

asp.net - 用数据库值填充 <ul>

javascript - 保存行程样式时出现问题