24

I'm very green to AngularJS. I'm wondering if it's possible to use it when your view is using HTML5 Canvas or WebGL? If so, are there any good tutorials on how you go about this?

I've seen several games boast they are made using AngularJS, but I don't know if that is limited to their menus, leaderboards, and other dashboard elements.

(I wouldn't necessarily be using MVC in a game, but obviously you can do more than just games with Canvas and WebGL.)

Thanks!

SpaceCowboy2071
  • 1,125
  • 1
  • 13
  • 20

2 Answers2

28

EDIT: I made a full example of a WebGL directive using three.js with bindings to resize the object or change it's material type. Also, events such as window resizing and mouse moved:


Yes this is very much possible. Beyond the menus, leaderboards, etc. you can wrap your canvas into a directive too.

  1. The controller will setup the game state
  2. Pass this state, loaded data from server and any other data you might have to the directive
  3. Finally you init the canvas in the directives link function

I made this little app to help me with a school project: http://callmethey.herokuapp.com/polygons. This is the directive I use (with three.js for the canvas part):

app.directive('polygon', function() {
  return {
    restrict: 'A',
    scope: { 
      vertices: '=polygon',  
      color: '=color'
    },
    link: function(scope, element, attrs)
    {
      var camera, scene, renderer;
      var polygon;
      var targetRotation = 0;
      var targetYRotation = 0, targetXRotation = 0;
      var targetYRotationOnMouseDown = 0, targetXRotationOnMouseDown = 0;
      var mouseX = 0, mouseY = 0;
      var mouseXOnMouseDown = 0, mouseYOnMouseDown = 0;
      var width = $(element).width();
      var height = 200;
      var widthHalfX = width/2;
      var widthHalfY = height/2;

      init();

      function init() {
        // Setup scene
        camera = new THREE.PerspectiveCamera( 70, width / height, 1, 1000 );
        camera.position.x = 0;
        camera.position.y = 0;
        camera.position.z = 300;
        scene = new THREE.Scene();
        // Build Polygon
        var geometry =  new THREE.Geometry();
        angular.forEach(scope.vertices, function (v) {
          geometry.vertices.push( new THREE.Vector3( v.x, v.y, v.z ) );
        });
        geometry.faces.push( new THREE.Face3(0, 1, 2 ));
        THREE.GeometryUtils.center( geometry );
        // Push polygon to scene
        var material = new THREE.MeshBasicMaterial( { color: cols[scope.color], side: THREE.DoubleSide } );
        polygon = new THREE.Mesh( geometry, material );
        scene.add(polygon);
        renderer = new THREE.WebGLRenderer();
        renderer.setSize( width, height );
      }

     // ..... rest of the code truncated for readability
  };
});
winkerVSbecks
  • 1,173
  • 1
  • 10
  • 24
  • 3
    WebGL directives, this has to be the future – jolySoft Nov 27 '13 at 13:39
  • Your examples dont work in chrome on mac. These errors are thrown: Error creating WebGL context. three.min.js:412 TypeError: Cannot call method 'getExtension' of null – Ivan Bacher Dec 13 '13 at 14:31
  • 1
    Chorome auto disables WEBGL on update sometimes. This seems to be an issue for older generation macbooks. Make sure chrome://flags/#disable-webgl is `disabled` and it will start working again. – winkerVSbecks Dec 13 '13 at 17:41
9

Another technique is to encapsulate the WebGL scene as a factory and expose access to the 3D scene to the module via the returned factory API. One advantage of this approach is that you can inject the scene into any other Controller or Directive. Factories in Angular are singletons so there is only 1 copy of the 3D scene floating around.

This encapsulation method also allows you to isolate both the 3D scene-logic from your application-logic.

You should be able to use MOST pre-existing WebGL code as long as you init the factory via the exposed Factory API. To do this, copy all your 3D scene code into a factory and then call an init function of the injected 3D factory from your controller to initialize rendering.

I used directives to on the canvas element to define the scene interaction. Click, marquee, keypress, events.

Angular and Three.js architecture demo

cubicleDowns
  • 121
  • 1
  • 3
  • 3
    Agreed! This should definitely be the approach if you have one WebGL context with several components that can be controlled and updated by angular. – winkerVSbecks Apr 11 '14 at 19:04
  • 3
    I've actually use this same approach to create multiple WebGL contexts. Simply create multiple factories and inject them all into the same controllers/directives you want to manipulate them from. If you use the requestAnimationFrame hook, the browser manages the FPS. – cubicleDowns Apr 12 '14 at 07:23