Introduction
This article is for developing labels for address or for barcodes by HTML Canvas. There are two parts in the article:
- Inner Canvas with fields
- Outer Canvas with repeat of inner canvas aligned
Background
I have an assignment in my web project to develop pattern for various label sizes. I found that it can be done by HTML Canvas. I also found many samples for canvas but none of them completely solved my requirement as I have to first develop inner canvas with fields and then with that canvas in repeat mode I want to form the outer canvas. After taking samples here and there, I was able to complete the assignment. I felt that sharing the complete assignment here would be helpful in future for developers to refer.
Using the Code
Now we will directly go to the code. I will post my MVC controller, HTML page and JavaScript code and will explain each.
Let us have a class for Label
having properties for dimensions for the labels called LabelType
.
public class LabelType
{
public string LabelTypeName; public int NoofLabelsperLine;
public int NoofLines;
public float LabelHeight;
public float LabelWidth;
public float LabelSpacingWidth;
public float LabelSpacingHeight;
public float LabelSpacingTop;
public float LabelSpacingLeft;
public Shape LabelShape;
public List<LabelItem> LabelItems; }
public class LabelItem : LabelAttribute
{
public string LabelItemname;
}
Now let us have the class for each field inside the label
called LabelItem
.
public class LabelItem : LabelAttribute
{
public string LabelItemname; }
public class LabelAttribute
{
public float HorizontalPosition; public float VerticalPosition;
public string FontName; public float FontSize; public bool IsBoldApplied;
public bool IsItalicApplied;
public bool IsActive;
}
Here is the enum
for shape
:
public enum Shape
{
Rectangle,
RoundRectangle,
Circle
}
Below is the Post
method in MVC controller that sets the dimension of the label.
[HttpPost]
public JsonResult GetLabelType(string data, string option)
{
LabelType param = new JavaScriptSerializer().Deserialize<LabelType>(data);
LabelType labelType = SetLabelType(option);
labelType.LabelItems = new List<LabelItem>();
for (int i = 0; i < 5; i++)
{
LabelItem labelItem = new LabelItem();
switch (i)
{
case 0:
labelItem.LabelItemname = "Dinesh Karthik";
break;
case 1:
labelItem.LabelItemname = "1st Street";
break;
case 2:
labelItem.LabelItemname = "Perungudi";
break;
case 3:
labelItem.LabelItemname = "Chennai";
break;
case 4:
labelItem.LabelItemname = "600103";
break;
}
labelItem.HorizontalPosition = param.LabelItems[i].HorizontalPosition * 96;
labelItem.VerticalPosition = param.LabelItems[i].VerticalPosition * 96;
labelItem.FontName = param.LabelItems[i].FontName;
labelItem.FontSize = param.LabelItems[i].FontSize;
labelItem.IsBoldApplied = param.LabelItems[i].IsBoldApplied;
labelItem.IsItalicApplied = param.LabelItems[i].IsItalicApplied;
labelItem.IsActive = param.LabelItems[i].IsActive;
if (labelItem.IsActive) labelType.LabelItems.Add(labelItem);
}
return new JsonResult
{ Data = labelType, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
The Positions are multiplied by 96 for inch to pixel conversion.
The function for Setlabeltype
is as below:
private LabelType SetLabelType(string labelName)
{
LabelType labelType = new LabelType();
switch (labelName)
{
case "lbAV5167":
case "lbAV5267":
case "lbAV5927":
labelType = SetLabelDims(0.5, 0.281, 0.5, 2.063, 0.5, 1.75, 4, 20);
break;
case "lbAV5295":
labelType = SetLabelDims(0.5, 0.625, 3.333, 3.937, 3.333, 3.333, 2, 3);
labelType.LabelShape = Shape.Circle;
break;
}
return labelType;
}
The code for SetLabelDims
is as follows:
private LabelType SetLabelDims(double SpacingTop, double SpacingLeft,
double SpacingHeight, double SpacingWidth,
double LabelHeight, double LabelWidth, int NumAcross, int NumDown)
{
LabelType labelType = new LabelType();
labelType.LabelSpacingTop = (float)SpacingTop * 96;
labelType.LabelSpacingLeft = (float)SpacingLeft * 96;
labelType.LabelSpacingHeight = (float)SpacingHeight * 96;
labelType.LabelSpacingWidth = (float)SpacingWidth * 96;
labelType.LabelHeight = (float)LabelHeight * 96;
labelType.LabelWidth = (float)LabelWidth * 96;
labelType.NoofLabelsperLine = NumAcross;
labelType.NoofLines = NumDown;
labelType.LabelShape = Shape.RoundRectangle; return labelType;
}
Now we will see the HTML and JavaScript for the scenario:
Below is the HTML code for controls to change the label dimensions by the user:
<div>
<label>Name</label>
<input id="isActiveName" type="checkbox" checked />
<input id="horizontalName"
class="customwidth" value=".1" type="number" />
<input id="verticalName"
class="customwidth" value=".25" type="number" />
<select id="fontNameName"></select>
<input id="fontSizeName"
class="customwidth" value="8" type="number" />
<input id="checkBoldName" type="checkbox" />
<input id="checkItalicName" type="checkbox" />
///Like the same give controls for Address 1,Address 2, City and Zip.
</div>
The id of each control will explain its purpose and I think there is no need to explain them in detail.
The screenshot is attached in Controls.png.
Now we will have two canvas
es. One is for outer div
which holds numeric labels inside and another one which is the inner label
.
<canvas id="canvas1"
style="border:1px solid #d3d3d3;background-color:white"></canvas>
<canvas id="canvas"
style="border:1px solid #d3d3d3;display:none"></canvas>
The dropdown for label
type selection is as below:
<select id="Labels"></select>
The dropdown is binded with label
names. I think the code for this is out of scope of this article and hence avoided to give here.
Now, we will see the JavaScript code for our case:
var selectLabel = document.getElementById('Labels').value;
var sample = {};
var LabelSample = {};
LabelSample.HorizontalPosition = document.getElementById("horizontalName").value;
LabelSample.VerticalPosition = document.getElementById("verticalName").value;
LabelSample.FontName = document.getElementById("fontNameName").value;
LabelSample.FontSize = document.getElementById("fontSizeName").value;
LabelSample.IsBoldApplied = $("#checkBoldName").prop('checked');
LabelSample.IsItalicApplied = $("#checkItalicName").prop('checked');;
LabelSample.IsActive = $("#isActiveName").prop('checked');
sample.LabelItems = [LabelSample];
sample = JSON.stringify(sample);
$.ajax({
type: 'POST',
url: '/Home/GetLabelType',
data: { data: sample, option: selectLabel },
dataType: "json",
async: false,
success: function (data) {
promise = data;
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
can.width = 816; can.height = 1056;
var pattern = document.getElementById('canvas');
var pctx = pattern.getContext('2d');
pattern.width = Math.round(promise.LabelWidth);
pattern.height = Math.round(promise.LabelHeight);
for (i = 0; i < promise.LabelItems.length; i++) {
pctx.font = promise.LabelItems[i].FontSize + "pt " + promise.LabelItems[i].FontName;
if (promise.LabelItems[i].IsBoldApplied) {
pctx.font = "bold" + " " + pctx.font;
}
if (promise.LabelItems[i].IsItalicApplied) {
pctx.font = "italic" + " " + pctx.font;
}
pctx.fillText(promise.LabelItems[i].LabelItemname,
promise.LabelItems[i].HorizontalPosition, promise.LabelItems[i].VerticalPosition);
}
if (promise.LabelShape == "0") {
pctx.beginPath();
pctx.moveTo(0, 0);
pctx.lineTo(promise.LabelWidth, 0);
pctx.moveTo(promise.LabelWidth, 0);
pctx.lineTo(promise.LabelWidth, promise.LabelHeight);
pctx.moveTo(promise.LabelWidth, promise.LabelHeight);
pctx.lineTo(0, promise.LabelHeight);
pctx.moveTo(0, promise.LabelHeight);
pctx.lineTo(0, 0);
pctx.closePath();
pctx.stroke();
}
else if (promise.LabelShape == "2") {
pctx.beginPath();
pctx.arc(promise.LabelWidth / 2,
promise.LabelHeight / 2, promise.LabelWidth / 2, 0, 2 * Math.PI);
pctx.closePath();
pctx.stroke();
}
else {
pctx.beginPath();
pctx.moveTo(0 + 19.2, 0); pctx.lineTo(0 + promise.LabelWidth - 19.2, 0);
pctx.quadraticCurveTo(0 + promise.LabelWidth, 0, 0 + promise.LabelWidth, 0 + 19.2);
pctx.lineTo(0 + promise.LabelWidth, 0 + promise.LabelHeight - 19.2);
pctx.quadraticCurveTo(0 + promise.LabelWidth, 0 +
promise.LabelHeight, 0 + promise.LabelWidth - 19.2, 0 + promise.LabelHeight);
pctx.lineTo(0 + 19.2, 0 + promise.LabelHeight);
pctx.quadraticCurveTo(0, 0 + promise.LabelHeight, 0, 0 + promise.LabelHeight - 19.2);
pctx.lineTo(0, 0 + 19.2);
pctx.quadraticCurveTo(0, 0, 0 + 19.2, 0);
pctx.lineWidth = .5;
pctx.closePath();
pctx.stroke();
}
var a = 0;
var b = 0;
for (i = 1; i <= promise.NoofLines; i++) {
for (j = 1; j <= promise.NoofLabelsperLine; j++) {
a = ((j - 1) * promise.LabelSpacingWidth + promise.LabelSpacingLeft);
b = ((i - 1) * promise.LabelSpacingHeight + promise.LabelSpacingTop);
ctx.drawImage(pattern, a, b, promise.LabelWidth, promise.LabelHeight);
}
}
}
})
}
I think the code is self explanatory and so did not explain each line of code.
- I have not used
Canvaspattern
because giving uniform space between patterns is difficult.
- I have referred in net and get the code for Rounded Rectangle in Canvas.
- Converting Check box value to boolean required prop('checked') function.
- There are many more difficulties I faced during the development of this project. I have integrated all and presented here.
- I have not aligned any controls properly in HTML as this is a mere sample and I think the logic is more important as this is not for end user.
I have attached the Label Pattern screenshot in the file Label_Pattern.png.
Please comment for any clarifications.
History
- 19th November, 2014: Initial version