SVG Physical Attraction (with Dart and Box2D)

A Box2D demo to show how to hook the physics engine up with SVG and the DOM.

The following code demonstrates how to 'hook-up' the SVG with box engine. An advantage of this approach is that SVG elements can revceive events (e.g. hover to change opacity).


import 'dart:html';
import 'dart:svg';
import 'dart:math';
import 'package:box2d/box2d.dart';  

//hint: add the package to your dart editor project by opening the 
//pubspec.yaml; adding Box2D under dependencies and then 
//running pub install via the link that will be at the top right of page    

...
    
World _world;
Map<String,TransformItem> _items = new Map<String,TransformItem>();    
    
main {    

  ...
    
  //use css selector to create a collection of svg elements to animate
  //(shapes defined in html doc as <path id="path_138" ... d="..."/> )
  queryAll("[id^="path"]").forEach((SvgElement e){
  
    //set the shape and position of the shape in the box2d world
    var rect = e.getBoundingClientRect();
    fixDef.shape = new CircleShape();
    fixDef.shape.radius = 5.0/SCALE;    
    bodyDef.position.x = (rect.left+rect.width/2)/SCALE;
    bodyDef.position.y = rect.top/SCALE;
  
    //link the svg element to the fixture via the id attribute
    bodyDef.userData = e.id;
  
    //TransformItem is a helper class for operating on the SVG Element
    //and is held in a Map for easy access, note the position is on 
    //SVG canvas not at world scale.
    TransformItem item = new TransformItem(e);
    item.center = new Vector(
      (rect.left+rect.width/2).toDouble(),
      (rect.top+rect.height/2).toDouble());
    _items[e.id] = item;
    
    //add the item to world
    Body b = _world.createBody(bodyDef);
    b.createFixture(fixDef);
    
    item.orginalMass = b.mass; //playing with mass to add the jitter effect
    
    //and add some user interaction
    e.onMouseOver.listen((_)=> _.currentTarget.attributes["opacity"] = "0.2");
    
  });

  requestAnimationFrame().then(update);

}
        

...and the update method for each animation frame...


dynamic update(num highResTime){

  _world.step(1/50,10,10); 
  _world.clearForces();
  
  requestAnimationFrame().then(update); //keep the show running
  
  //iterate through each box body
  for(Body b = _world.bodyList; b != null; b = b.next){
  
    if(b.type!=BodyType.STATIC){
      
      //set up the relationship between body and point of attraction 
      Vector itemPosition = b.position;
      Vector targetPosition = _targetPointOfAttraction;
      Vector targetDistance = new Vector.zero(); 
      targetDistance.addLocal(itemPosition);
      targetDistance.subLocal(targetPosition);
      num finalDistance = targetDistance.length;
      targetDistance.negateLocal();
      //divsors reduce the magnitude of force
      targetDistance = new Vector(targetDistance.x/50,targetDistance.y/50);

      //get the svg element's helper object
      TransformItem path = _items[b.userData]; 
      
      //playing around with mass
      double multiplier = 1+1.1755*(_random.nextBool()?1:-1);
      b.mass = _random.nextBool()? b.mass * multiplier: path.orginalMass;
      
      //apply the attraction (comment this out for falling elements)      
      b.applyForce(targetDistance, b.position);
      
      //translate the position of the svg Element
      path.setTransform(
          new Vector(b.position.x, b.position.y),
          b.originTransform.rotation.toString());
      
      //play around with opacity for effect
      double opacity = double.parse(path.element.attributes["opacity"]);
      path.element.attributes["opacity"] = "${opacity + 0.02 * (_random.nextBool()?-1:1)}";
      
    }
    
  }
  
}          
          
        

Currently having problems running in IE (as at 2013-07-06).

View the full source code here and see the references below for tutrials on working with Box2D. For more info on the Dart Programming Language see dartlang.org.

Reference:

Our Google+ SVG-Developers community is brand new and looking for members. There is also a space here for your SVG links, examples and tutorials.