Aside from my work project in AngularJS, I've also got a private project in Angular, and the stuff I'm doing there is actually a bit more complicated: I'm working on a game (who isn't?) that has a map showing the current positions of a number of (space) fleets and planets. Fleets can have a number of waypoints (places they move to over the next couple of turns). All of this is drawn in SVG.
I'm currently using Raphael as my SVG library because it's popular and probably good. Handling interaction between Angular and Raphael was originally quite easy to do with the use of $watch and $apply. For example, you could select a fleet or a planet either on the (SVG) map or in a list outside it, and the data for it would be shown, and it would be highlighted on the map. This worked well. The latest feature I added turned it into quite a mess, though. I wanted the ability to add new waypoints to a fleet. First press a button outside the map area to switch to the "add waypoint" mode. Then click on the map where you want the new waypoint. The way point gets added to the data, and is immediately shown in the fleet data outside the map, as well as detected by a $watch and drawn on the map. This has led to the following hideous piece of code: $scope.$watch('selected', function(selected, oldselected) { console.log("selected changed"); if (selected !== oldselected && selected !== null) { if (selected.fleet) { $scope.$watchCollection('selected.waypoints', function() { $scope.selected.shape.remove(); $scope.drawFleet(selected); }); selected.shape.attr({"fill": $scope.mapconfig.selectedfleetcolour, "stroke": $scope.mapconfig.selectedfleetcolour}); } else if (selected.planet) { selected.shape.attr({"fill": $scope.mapconfig.selectedplanetcolour, "stroke": $scope.mapconfig.selectedplanetcolour}); } if (oldselected !== null) { if (oldselected.fleet) { oldselected.shape.attr({"fill": $scope.mapconfig.fleetcolour, "stroke": $scope.mapconfig.fleetcolour}); } else if (oldselected.planet) { oldselected.shape.attr({"fill": $scope.mapconfig.planetcolour, "stroke": $scope.mapconfig.planetcolour}); } } } }) $scope.$watch('mode', function(mode, oldmode) { console.log("mode changed"); if (mode == 'addWaypoint') { console.log("addWaypoint"); iElement.on('mousemove', function($event) { $scope.mousecoords.x = $event.offsetX; $scope.mousecoords.y = $event.offsetY; $scope.$apply(); }) iElement.on("click", function(event) { $scope.addWaypoint({x: event.offsetX, y: event.offsetY}); $scope.setMode(oldmode); $scope.$apply(); }); } else if (oldmode == 'addWaypoint') { iElement.off("mousemove click"); } }) I'm setting watchers and even handlers inside watchers. I'm pretty sure that's needlessly complicated. I don't doubt that there's already a dozen bugs in this. But most of all, by doing it this way, I'm working in a very non-Angular way. To combine Angular with this library (and I suspect the same would be true for any non-Angular library), I need to switch from the declarative Angular way to the more procedural traditional javascript way. It almost feels like I'm using $watch to do my DOM manipulation explicitly in JQuery. Fortunately, the cool thing about SVG is that, unlike Canvas, it's XML, and I think it's part of the DOM of the page. I suspect I could manipulate that DOM through Angular directly, instead of through some library. Originally I chose the library because I'm totally new to SVG, and it feels nice to have a nice library to do complex things for me, but now I think it's getting in my way. Or in Angular's way. Maybe I should drop it and manipulate the SVG directly with ngRepeats, Angular's data bindings and event handlers. Another option would be to use an SVG library designed to work with Angular, if one exists. Does one exist? Would that be better than the direct approach? So what does everyone here think the direct approach? Would it work? One thing I fear is that it would create a lot of data binding that would all be checked on every $digest, whereas I know that only the currently selected fleet can actually have waypoints added. So watching them all seems like it might grow into a serious performance overhead. Particarly if this game might eventually end up with hundreds of fleets and other objects. Or more. Who knows? So I've got a ton of data, but most of the time, most of it is pretty static. Is dynamically adding and removing $watches still a better way to go, despite the uglier code? (I'm also thinking this might be an interesting topic for a blog post. I've been thinking of starting a blog, and this might be a good topic to start with.) mcv. -- You received this message because you are subscribed to the Google Groups "AngularJS" group. To unsubscribe from this group and stop receiving emails from it, send an email to angular+unsubscr...@googlegroups.com. To post to this group, send email to angular@googlegroups.com. Visit this group at http://groups.google.com/group/angular. For more options, visit https://groups.google.com/groups/opt_out.