I have built a simple banner creation tool - it essentially allows the user to add text, apply fonts/colors/font size, add borders etc. Its mostly working but I am having trouble getting a border to apply to the new image and applying subtext. Not only will the border not appear, but the border width is changing the text stroke/outline width.
Regarding adding subtext, I need a subtext to go beneath the main text (working) that is centered in the image. I need the subtext to be about 20% the size of the main text. My code below does not contain anything for the subtext - because after seeing the border lineWidth mess with the main text I fear any subtext code will mess with the main text code.
#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 ;
}
}
There are just two little mistakes in your code.
Let's take a look at the following part of your code:
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);
Here we can see you're querying borderWith
and in case it's not zero draw a border. So at this point you definitely have a border. The issue starts with the next bit of code:
thisContext.fillRect(0,0,x,y);
This will essentially clear your whole canvas with the current fill style. You need to make this the first drawing operation generally. e.g.
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);
}
In this code block we can see that the text's stroke is determined by a variable called lineWidth
.
case "stroke":
thisContext.lineWidth = lineWidth ;
thisContext.strokeStyle = textStrokeColor;
thisContext.strokeText(bannerText, xPosition, yPosition);
break;
Problem is: you don't have a variable that name so it's taking the html <input>
element with an id of lineWidth which returns nonsense and the canvas will take the last value of thisContext.lineWidth
which has been the thickness of the border.
Just add a
var lineWidth = document.getElementById("lineWidth").value;
at the beginning of your buildBanner()
function.