New widget tutorial - canvas 2d example

1,227 views
Skip to first unread message

Witold Szczerba

unread,
Apr 10, 2011, 12:48:38 PM4/10/11
to ang...@googlegroups.com
Hi there,
I am experimenting with widgets on a canvas example. I am not sure how
this should be done, because in contrast to text fields and others
like it, the canvas is to be operated using it's API. This is what I
have prepared:

angular.widget('canvas', function(compileElement) {
var compiler = this;
var name = compileElement.attr('name');
var canv2d = compileElement[0].getContext('2d');
return function(linkElement) {
var scope = this;
scope.canv2d = scope.canv2d || {};
scope.canv2d[name] = canv2d;
};
});

function MainCtrl() {
var self = this,
height = 15;
this.text = 'type';
this.$watch('text', function(newValue, oldValue) {
if (self.canv2d && self.canv2d['theBoard']) {
var theBoard = self.canv2d['theBoard'];
theBoard.fillText(newValue, 0, height);
height += 15;
}
});
}

<!doctype html>
<html xmlns:ng="http://angularjs.org">
<script src="http://code.angularjs.org/angular-0.9.14.min.js"
ng:autobind></script>
<script src="sinus.js" ng:autobind></script>
<body ng:controller="MainCtrl">
<input name="text"><br>
<canvas width="1000" height='500' name="theBoard"></canvas>
</body>
</html>

The problem I see here is that MainCtrl is now operating directly on
DOM element.

What do you think? I am not asking for a solution, because I do not
need canvas elements, this is just a testing ground.

Thanks,
Witold Szczerba

Igor Minar

unread,
Apr 10, 2011, 1:13:14 PM4/10/11
to ang...@googlegroups.com, Witold Szczerba
Hi there!

Your are right, if controller does dom manipulation the code starts to smell.


/i


--
You received this message because you are subscribed to the Google Groups "Angular" group.
To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/angular?hl=en.


Igor Minar

unread,
Apr 10, 2011, 4:30:57 PM4/10/11
to Witold Szczerba, ang...@googlegroups.com
+angular

Yeah, my solution was very simple and not generic one.

I think that creating a generic solution will be a non-trivial task because canvas api can do so much. It would be much easier to create a set of specialized canvas widgets just like I did in my previous example.

However, your idea with message buss service integration is definitely the right way to go if implementing a generic solution.

btw overriding the behavior of <canvas> is not ideal in this case. I think that you should define new tags for these specialized canvas widgets e.g. <mycanvas:logger>.

Lastly, when it comes to angular integration with 3rd party widgets, sometimes it's trivial, other times it's not. We've been able to itegrate several jquery ui widgets with angular. I believe the related discussion is archived on this list. I think YUI widgets will be  similar case. However in the case of ExtJS, I fear that because ExtJS takes control over entire DOM, we won't be able to integrate with them easily.

/i






On Sun, Apr 10, 2011 at 11:58 AM, Witold Szczerba <pljos...@gmail.com> wrote:
Thanks Igor!
Yes, well. Your solution was just to move the DOM manipulation into
the widget definition. The result it: there is no DOM manipulation in
controller any more, but now the 'canvas' widget is extremely limited
- it can draw the text and nothing more.
On the other hand - the more focused widgets are - the simpler the
controllers are, simpler controllers are easier to test, etc...

I was thinking also about something else. If I would wrap the canvas
with my own, simple API, the one I would discover useful - then the
controller would not 'touch' the DOM element directly and it would be
easy to mock it. What do you think? If that is acceptable: how should
the controller come into possession of that wrapper? In my original
sample, I pushed the DOM element into controller - to be honest, I do
not like it, because looking at controller, we have not idea where
does the 'canv2d' come from. It looks like there are more problems
than solutions here :/

Yet yet another solution, the last that comes to my mind, and I
promise, no more 'crazy solutionz' in my head :) would be an event bus
service. Widgets would register listeners and controllers would post
commands to the message queue. But in the (very very) end - how does
the event bus is different from API and object wrapper?

The reason I am provoking discussion here is that, while Angular is,
in my opinion, one of the best thing I have ever seen (I am Java
developer: from Swing GUI to Java EE and database procedures), as of
now, it lacks some kind of widget integration guidelines... How should
the jQuery UI, like jDialog be used? If and if so, how could we
integrate angular with ExtJS? They have some nice components. How
about Yahoo UI?

Best regards,
Witold Szczerba


2011/4/10 Igor Minar <iim...@gmail.com>:

Witold Szczerba

unread,
Apr 10, 2011, 6:12:55 PM4/10/11
to Igor Minar, ang...@googlegroups.com
Here is the very first, lame and immature attempt to implement my
example using an event bus:

angular.service('ebus', function() {
var listeners = [];
return {
register: function(name, listener) {
listeners.push({name:name,listener:listener});
},
sendMsg: function(name) {
for (var i in listeners) {
if (listeners[i].name == name) {
listeners[i].listener.apply(this, arguments);
return;
}
}
}
};
});

angular.widget('canvas', function(compileElement) {
var compiler = this;
var name = compileElement.attr('name');
var canv2d = compileElement[0].getContext('2d');

var height = 15;


return function(linkElement) {
var scope = this;

var ebus = scope.$service('ebus');
ebus.register(name+':write', function(name, text) {
canv2d.fillText(text, 0, height);
height += 15;
});
};
});

function MainCtrl(ebus) {
var self = this;


this.text = 'type';
this.$watch('text', function(newValue, oldValue) {

ebus.sendMsg('theBoard:write', self.text);
});
}
MainCtrl.$inject = ['ebus'];

The HTML remains as it was in my first post (<canvas ... name='theBoard'>...).

The canvas widget registers a listener using it's name and action's
name as an identifier and controller sends a message using text as a
payload. Of course this is an early prototype (written by a guy who
sometimes writes Java code in one day more than JavaScript code in his
entire live), but I wanted just to try the idea. More serious approach
could take the scope's visibility-range into an account, so having
several canvases named "theBoard" with several controllers (one canvas
per one controller in one DOM) would not interfere. Example:

<div ng:controller='SomeController'>
Board one:
<canvas .... name='theBoard'></canvas>
</div>
<div ng:controller='SomeController'>
Board two:
<canvas .... name='theBoard'></canvas>
</div>

As I said before, I really do not need those canvases, just playing
with Angular and JavaScript to stay in touch with this technology, as
my current job pushes me into the abyss.

Regards,

Igor Minar

unread,
Apr 10, 2011, 6:17:08 PM4/10/11
to Witold Szczerba, ang...@googlegroups.com
yeah, this will work for simple stuff. the canvas widget currently responds only to one kind of message, but that could be extended.

I actually find combining angular and inlined svg more exciting than canvas. With inlined svg, you can just create angular bind points using double curlies or ng:bind directly in svg without the hassle of translation between the world of html/js and svg.

/i

Witold Szczerba

unread,
Apr 10, 2011, 7:52:05 PM4/10/11
to Igor Minar, ang...@googlegroups.com
You are right, but I have picked canvas only to try the possible
options to deal with some third-party widgets. What if we would
replace canvas example with something like charts, spreadsheets/data
grids, dialogues or whatever else they would come up with...
Considering spreadsheet-like tables or data grids - one can produce
HTML table using a template or pick up some JavaScript-driven, ready
to use, fancy grids with sophisticated API - as always, there is no
single solution to solve all the cases.

Thanks,
Witold Szczerba

2011/4/11 Igor Minar <iim...@gmail.com>:

Reply all
Reply to author
Forward
0 new messages