EnyoJS Tutorial #12 – EnyoCanvas!

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 (698 downloads)

 

Comments

comments