Today, we will be covering in depth about EnyoJS’s canvas library.
That’s right – The ever growing popularity of HTML5 canvas.
First of all, a note to all that eager to cross into this canvas area. If you are thinking about making an all rounder cross platform (inclusive of Android 2.2 all the way to Android 4, Windows Phone 8 and IOS etc) – Well, forget it don’t even bother..
To be safe, canvas and worker of html5 works best only in platform such as IOS 5+, Android 4+, Window Phone 8 and BB10. Same again it’s the IE6 dilemma, my advise is…just go ahead and do it – ditch the old phones, they will get new ones anyway!
Anyway, let’s move on. First of all, a side note, not all ui library are deployed with the bootplate. UI libraries like Enyo.Canvas is developed separately. You can get them here https://github.com/enyojs/canvas
Once, you download them place the canvas folder into lib. Link em up in your source folder’s package.js
1 2 3 4 5 6 7 8 9 10 | enyo.depends( "$lib/layout", "$lib/onyx", "$lib/canvas", "../assets/css/app.css", "common", "Footer.js", "Header.js", "App.js" ); |
Alright, instead of playing with primitive stuff like drawing a line and circle, we are going to make something useful. How about drawing a custom bar chart like the one below?
And we are going to achieve it with the help of the canvas library. The canvas library by enyo allow us to develop canvas using enyo like syntax.
Note: This library is currently under development, it lacks the fittable controls over it. To size the canvas object, you would have to use attributes node.
CanvasChart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | enyo.kind({ name: "CanvasChart", components:[ { style:"height:20px" }, { style:"text-align:center !important; height:320px", components:[ { name:"canvas", kind: "Canvas", attributes: {width: 320, height: 320}, style:"border:1px solid #fff;background:#fff" } ] } ], handlers:{ //Waterfall event from the button from parent's footer. onPlotGraph:"handlePlotGraph" }, published:{ data:{ xlabels:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"], ylabels:[0,100,200,300,400,500,600,700,800,900,1000,1100,1200], values:[200,250,400,300,500,700,800,400,500,550,700,1100], colors:["blue","red","green","yellow","orange","lime","gold","violet","pink","maroon","purple","magenta"] }, cellIncrement:10 }, create: function() { this.inherited(arguments); }, rendered:function(){ this.inherited(arguments); // 1. Let's draw some grid, using rectangles and fill up 320px with 10x10 boxes. this.drawGrid(); // 2. Then, the defining guide lines for X and Y. this.drawXYLines(); this.drawLabels(); }, drawGrid:function(){ for (var y = 0; y < 32; y++) { for (var x = 0; x < 32; x++) { this.$.canvas.createComponent( { kind: "enyo.canvas.Rectangle", bounds:{t:(x*this.cellIncrement), l:(y*this.cellIncrement), w:10, h:10}, color:"#ffffff", outlineColor:"#cccccc" } ); } } this.$.canvas.render(); }, drawXYLines:function(){ //Drawing the Y GuideLine this.drawRect(10,30,2,320-40); //Drawing the X GuideLine this.drawRect(290,30,320-50,2); }, drawLabels:function(){ //Drawing label based on function drawLabels. //Draw based on Y first. for (var y = 0; y < this.data.ylabels.length; y++) { // From bottom l:30, t:280 but we use 295 because, each label is +10px of height +5 to centerize it to the grid to top. // But labels have to start slightly to the left. // Always trace/log the plotted top for reference. console.log("value : " + this.data.ylabels[y] + " is at coordinate top "+(295-(y*(this.cellIncrement*2)))); this.drawText(this.data.ylabels[y],295-(y*(this.cellIncrement*2)),28,50,10,"right"); } for (var x = 0; x < this.data.xlabels.length; x++) { // From bottom l:30, t:280 but we use 295 because, each label is +10px of height +5 to centerize it to the grid to top. // But labels have to start slightly to the left. // Always trace/log the plotted left reference. console.log("value : " + this.data.xlabels[x] + " is at coordinate left "+(50+(x*(this.cellIncrement*2)))); this.drawText(this.data.xlabels[x],305,50+(x*(this.cellIncrement*2)),60,10,"center"); } }, handlePlotGraph:function(){ this.plotGraph(); }, plotGraph:function(){ for (var x = 0; x < this.data.values.length; x++) { // Finding the height of each bar // based on our ratio 20px is 100 unit // So, 1px = 5 unit. // Remember the actual line of 0 starts from 290 not 295, // thats just for label positioning. var realPlottedTop = this.data.values[x]/5; // The height of the bar is always the computed value of the ratio. // The top is measured by computed height - the actual 0's top. // 20px is just the bar width. // color is assigned via this.data.color. this.drawRect(290-Math.round(realPlottedTop),40+(x*(this.cellIncrement*2)),20,Math.round(realPlottedTop),this.data.colors[x]); } }, drawRect:function(top,left,width,height,color){ if (arguments.length<5) { this.$.canvas.createComponent( { kind: "enyo.canvas.Rectangle", bounds:{t:top, l:left, w:width, h:height}, color:"#aaa" } ); } else { this.$.canvas.createComponent( { kind: "enyo.canvas.Rectangle", bounds:{t:top, l:left, w:width, h:height}, color:color } ); } this.$.canvas.render(); }, drawText:function(label,top,left,width,height,align){ this.$.canvas.createComponent( { kind: "enyo.canvas.Text", bounds:{t:top, l:left, w:width, h:height}, color:"#333", align: align, font:"Arial 12pt", text:label } ); this.$.canvas.render(); } }); |
And this is the source for App.js. It’s design to trigger a waterfall to plot the graph.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | enyo.kind({ name: "App", kind: "FittableRows", classes: "enyo-fit enyo-unselectable contentBg", components: [ { kind:"Header" }, { fit:true, kind:"CanvasChart" }, { kind:"Footer",onFooterButtonTapped:"handlePlotGraph" } ], create: function(){ this.inherited(arguments); }, handlePlotGraph:function(inSender,inEvent) { this.waterfall("onPlotGraph"); } }); |
Like the usual, today’s Canvas Jutsu tutorial file…
EnyoJS Tutorial #12 (1513 downloads)