Canvas 边框不起作用以及如何向 canvas 添加潜台词

Canvas border not working and how to add subtext to canvas

我已经构建了一个简单的横幅创建工具 - 它基本上允许用户添加文本、应用 fonts/colors/font 大小、添加边框等。它主要工作但我无法将边框应用到新图像和应用潜台词。不仅不会出现边框,而且边框宽度在改变文字stroke/outline宽度

关于添加潜台词,我需要一个潜台词放在位于图像中心的正文(工作)下方。我需要副文本大约是正文大小的 20%。我下面的代码不包含任何子文本 - 因为在看到边框 lineWidth 与主文本混淆后,我担心任何子文本代码都会与主文本代码混淆。

#HTML

                     <div id="createBanner" class="form-row rowSpacing" style="display:none;">
                          <div class="form-row rowSpacing">
                            <div class="form-group col-md-5">
                              Select Banner Text:
                              <div style="margin-left:25px;">
                                <input type="radio" name="textType" id="textType1" value="1" onchange="buildBanner();" checked="checked"> <span id="bannerText1"></span> (Full Org Name)
                                <br><input type="radio" name="textType" id="textType2" value="2" onchange="buildBanner();" > <span id="bannerText2"></span> (Short Org Name)
                              </div>
                            </div>
                          </div>
                          <div class="form-row rowSpacing">
                            <div class="form-group col-md-5" style="display:block;">
                              <div>
<?php 
    helpButton($buttonID++,"Some browsers may not support all the listed fonts") ;
?>                                 
                                Select Font: 
                                <select id="fontFace" onchange="buildBanner();" >                                  
                                  <option selected value="Arial">Arial (sans-serif)</option>
                                  <option value="Arial Black">Arial Black" (sans-serif)</option>
                                  <option value="Verdana">Verdana (sans-serif)</option>
                                  <option value="Tahoma">Tahoma (sans-serif)</option>
                                  <option value="Trebuchet MS">Trebuchet MS (sans-serif)</option>
                                  <option value="Impact">Impact (sans-serif)</option>
                                  <option value="Times New Roman">Times New Roman (serif)</option>
                                  <option value="Didot">Didot (serif)</option>
                                  <option value="Georgia">Georgia (serif)</option>
                                  <option value="American Typewriter">American Typewriter (serif)</option>
                                  <option value="Andalé Mono">Andalé Mono (monospace)</option>
                                  <option value="Courier">Courier (monospace)</option>
                                  <option value="Lucida Console">Lucida Console (monospace)</option>
                                  <option value="Monaco">Monaco (monospace)</option>
                                  <option value="Bradley Hand">Bradley Hand (cursive)</option>
                                  <option value="Brush Script MT">Brush Script MT (cursive)</option>
                                  <option value="Luminari">Luminari (fantasy)</option>
                                  <option value="Comic Sans MS">Comic Sans MS (cursive)</option>                                  
                                </select>
                              </div>
                              <div style="margin-top:20px;">
                                Font Size: <input type="range" id="fontSize" min="25" max="200" step="1" onchange="buildBanner();" value="100"/>
                              </div>
                              <div style="margin-top:20px;">
                                Font Style: 
                                <select id="fontStyle" onchange="buildBanner();" >
                                  <option value="normal">Normal</option>
                                  <option value="italic">Italic</option>      
                                  <option value="oblique">Oblique</option>
                                </select>
                              </div>
                              <div style="margin-top:20px;">
                                Font Weight: 
                                <select id="fontWeight" onchange="buildBanner();" >
                                  <option selected value="normal">Normal</option>
                                  <option value="bold">Bold</option>      
                                  <option value="bolder">Bolder</option>      
                                  <option value="lighter">Lighter</option>        
                                </select>
                              </div>
                            </div>
                            <div class="form-group col-md-5" style="display:block;">
                              <div>
                                Text Color Fill Type: 
                                <select id="fillType" onchange="buildBanner();" >
                                    <option selected value="colorFill">Color Fill</option>
                                    <option value="linearGradient">Linear Gradient</option>
                                    <option value="radialGradient">Radial Gradient</option>
                                </select>
                              </div> 
                              <div style="margin-top:20px;">
                                Text Fill or Outline : 
                                <select id="strokeType" onchange="buildBanner();" >
                                    <option selected value="fill">Fill</option>
                                    <option value="stroke">Outline</option>
                                </select>
                              </div>
                              <div style="margin-top:20px;">
                                If outline, line thickness: <input type="range" id="lineWidth" min="1" max="10" step="1" onchange="buildBanner();" value="2"/>
                              </div>                            
                              <div style="margin-top:20px;">
                                Text Color: <input type="color" id="textFillColor" onchange="buildBanner();" value="#000000"/>
                              </div>
                            </div>
                          </div>
                          
                          <div class="form-row rowSpacing">
                            <div class="form-group col-md-5" style="display:block;">
                              <div>
                                Background Color: <input type="color" id="bgFillColor" onchange="buildBanner();"  value="#ffffff"/>
                              </div>                            
                              <div style="margin-top:20px;">
                                Border width: <input type="range" id="borderWidth" min="0" max="10" step="1" onchange="buildBanner();" value="0"/>
                              </div>  
                              <div style="margin-top:20px;">
                                Border Color: <input type="color" id="borderColor" onchange="buildBanner();" value="#000000"/>
                              </div>                              
                            </div>
                          </div>

                          <div style="">
                            <canvas id="realCanvas" width="1200" height="300" style="width:25vw;">
                                Your browser does not support Canvas.
                            </canvas>                            
                            <textarea id="imageDataDisplay" rows=5 cols=100 style="display:none;"></textarea>
                          </div>                          
                        </div>

#JS

function canvasSupport () {
   return !!document.createElement("canvas").getContext;
}

function buildBanner () {
  Debugger.log("Drawing Canvas");
  
  if(!canvasSupport()) {
      return;
  }
  
  var wCanvas = 1200 ;
  var hCanvas = 300 ;
  
  var realCanvas = document.getElementById('realCanvas');
  var realContext = realCanvas.getContext('2d');
  
  var text1 = document.getElementById('textType1') ;
  var text2 = document.getElementById('textType2') ;
  
  if (text1.checked) {
    var bannerText = document.getElementById('cVendor').value ;
    console.log("Text1: "+ bannerText) ;
  } else if (text2.checked) {
    var bannerText = document.getElementById('cVendorName').value ;
    console.log("Text2: "+ bannerText) ;
  }
  
  var textStrokeColor = "#000000";
  var textBaseline = "middle";
  var textAlign = "center";
  
  // This is the event handler for listening for a key up event in the text box form
  // It will call the textBoxChanged function to update the text in the canvas
  
  var fontSize = document.getElementById("fontSize").value;
  var fontFaceSelect = document.getElementById("fontFace");
  var fontFace = fontFaceSelect.options[fontFaceSelect.selectedIndex].value ;
  var fontWeightSelect = document.getElementById("fontWeight");
  var fontWeight = fontWeightSelect.options[fontWeightSelect.selectedIndex].value ;
  var fontStyleSelect = document.getElementById("fontStyle");
  var fontStyle = fontStyleSelect.options[fontStyleSelect.selectedIndex].value ;
  
  var fillTypeSelect = document.getElementById("fillType");
  var fillType = fillTypeSelect.options[fillTypeSelect.selectedIndex].value ;
  var strokeTypeSelect = document.getElementById("strokeType");
  var strokeType = strokeTypeSelect.options[strokeTypeSelect.selectedIndex].value ;
  var strokeWidth = document.getElementById('strokeWidth').value ;
  
  var borderColor = document.getElementById("borderColor").value ;
  var borderWidth = document.getElementById("borderWidth").value ;
  
  var textFillColor = document.getElementById("textFillColor").value ;
  var bgFillColor = document.getElementById("bgFillColor").value ;
  var imageData = document.getElementById("createImageData");
  
  realContext = drawScreen(realContext,wCanvas,hCanvas,1);       
  
  var imageDataDisplay = document.getElementById("imageDataDisplay");
  imageDataDisplay.value = realCanvas.toDataURL();  
  
  function drawScreen(thisContext,x,y,xSize) {
    thisContext.clearRect(0, 0, x, y);
  
    var metrics = thisContext.measureText(bannerText);
    var textWidth = metrics.width;
    var xPosition =  x / 2
    var yPosition =  y / 2;

    // Draws the Text Box
    thisContext.globalAlpha = 1.0;
    thisContext.fillStyle = bgFillColor ;
    thisContext.fillRect(0,0,x,y);
    
    if (borderWidth != 0) {
      thisContext.strokeStyle = borderColor ;
      thisContext.lineWidth = borderWidth ;  
      console.log(borderColor+ " : " +borderWidth) ;
      thisContext.strokeRect(0, 0 , x-borderWidth, y-borderWidth) ;
    }

    
    // Draws the actual text
    var xFontSize = fontSize * xSize ;
    thisContext.font = fontWeight + " " + fontStyle + " " + xFontSize + "px " + fontFace;
    thisContext.textBaseline = textBaseline;
    thisContext.textAlign = textAlign;

    var tempColor;
    switch(fillType) {
      case "colorFill":
          Debugger.log("Color Fill");
          tempColor = textFillColor;
          break;
      case "linearGradient":
          Debugger.log("Linear Gradient");
          var linGradient = thisContext.createLinearGradient(xPosition-textWidth/2, yPosition, xPosition+textWidth/2, yPosition);
          linGradient.addColorStop(0, textFillColor);
          tempColor = linGradient;
          break;
      case "radialGradient":
          Debugger.log("Radial Gradient");
          var radGradient = thisContext.createRadialGradient(xPosition, yPosition, 1, xPosition, yPosition, textWidth/2);
          radGradient.addColorStop(0, textFillColor);
          tempColor = radGradient;
      break;
    }

    switch(strokeType) {
      case "fill":
          thisContext.fillStyle = tempColor;
          thisContext.fillText(bannerText, xPosition, yPosition);
          break;
      case "stroke":
          thisContext.lineWidth = strokeWidth ;  
          thisContext.strokeStyle = textStrokeColor;
          thisContext.strokeText(bannerText, xPosition, yPosition);
          break;
      case "both":
          thisContext.fillStyle = tempColor;
          thisContext.fillText(bannerText, xPosition, yPosition);
          thisContext.strokeStyle = textStrokeColor;
          thisContext.strokeText(bannerText, xPosition, yPosition);
          break;
    }
    return thisContext ;
  }
}

您的代码中只有两个小错误。

#1 缺少边框

让我们看一下您的代码的以下部分:

if (borderWidth != 0) {
  thisContext.strokeStyle = borderColor ;
  thisContext.lineWidth = borderWidth ;  
  console.log(borderColor+ " : " +borderWidth) ;
  thisContext.strokeRect(0, 0 , x-borderWidth, y-borderWidth) ;
}

//Add BACKGROUND color

thisContext.fillStyle = bgFillColor ;
thisContext.fillRect(0,0,x,y);

在这里我们可以看到您正在查询 borderWith,如果它不是零,请画一个边框。所以在这一点上你肯定有一个边界。问题从下一段代码开始:

thisContext.fillRect(0,0,x,y);

这基本上会用当前的填充样式清除整个 canvas。您通常需要将其作为第一个绘图操作。例如

thisContext.globalAlpha = 1.0;
thisContext.fillStyle = bgFillColor;
thisContext.fillRect(0,0,x,y);
if (borderWidth != 0) {
  thisContext.strokeStyle = borderColor ;
  thisContext.lineWidth = borderWidth ;  
  console.log(borderColor+ " : " +borderWidth) ;
  thisContext.strokeRect(0, 0 , x-borderWidth, y-borderWidth);
}

#2 边框宽度影响文字笔画

在此代码块中,我们可以看到文本的笔画由名为 lineWidth 的变量确定。

  case "stroke":
      thisContext.lineWidth = lineWidth ;  
      thisContext.strokeStyle = textStrokeColor;
      thisContext.strokeText(bannerText, xPosition, yPosition);
      break;

问题是:您没有那个名称的变量,所以它使用 ID 为 lineWidth 的 html <input> 元素,returns 废话和 canvas 将采用 thisContext.lineWidth 的最后一个值,即边框的粗细。 只需添加一个

var lineWidth = document.getElementById("lineWidth").value;

buildBanner() 函数的开头。