D3 + Angular

The plan

Angular directives (credit)

D3.js review (scatter-plot)

D3 in angular (<scatter-plot>)

{angular-directives}

Directives review

HTML attributes that attach behaviors

Render multiple elements

<input ng-model="search" />
<div>
    <p ng-repeat="ele in myData">{{ele}}</p>
</div>

Writing directives

Directive method in JS

var myApp = angular.module("myApp", [])

// Add controller
myApp.controller('Ctrl', function($scope) {
  $scope.customer = {
    name: 'Naomi',
    address: '1600 Amphitheatre'
  };
})

// Create a directive for this app
myApp.directive('myCustomer', function() {
  return {
    template: 'Name: {{customer.name}} Address: {{customer.address}}'
  };
});

Writing directives

Apply directive in HTML

<div ng-app="myApp" ng-controller="Controller">
  <div my-customer></div>
</div>

Better yet...

Use a templateUrl

Need to create a new .html fragment

app.directive('myCustomer', function() {
    return {
      templateUrl: 'my-customer.html'
    };
  });
<!-- myCustomer.html -->
<p>Name: {{customer.name}} Address: {{customer.address}}</p>

Better yet...

Create your directive as a new HTML element!

Include it in your HTML

 app.directive('myCustomer', function() {
    return {
      restrict: 'E', // restrict to a new type of element
      templateUrl: 'my-customer.html'
    };
  });
<!-- index.html -->
<body ng-app="docsRestrictDirective">
  <div ng-controller="Controller">
  <my-customer></my-customer>
</div>

Better yet...

Structure to pass in data

Pass data in HTML elements

app.directive('myCustomer', function() {
    return {
      restrict: 'E',
      scope: {
        customerInfo: '=info'
      },
      templateUrl: 'my-customer-iso.html'
    };
  });
<div ng-controller="Controller">
  <my-customer info="naomi"></my-customer>
  <hr>
  <my-customer info="igor"></my-customer>
</div>

{exercise(?)}

{D3 scatter-plot}

Start in the same place

Fork my repo

Clone in desktop

Start your local server

cd "d3-demo"
python -m SimpleHTTPServer 8080

Scales

// Write a function to set your scales
	var setScales = function() {
		// xScale
		

		// yScale		
	}

Positioning Function

/* Write a function to define the positioning of your circles
		- cx attribute as the 1960 life expectancy
		- cy attribute as the 2013 life expectancy
		- title attribute as the country of the object
	*/

Draw function

// Write a reusable drawing function for circles
	var draw = function(data) {
	    // Set Scales
		
		
	    // Select all circles and bind your data to them
		
	
            // Use the .enter() method to get your entering elements, and then position them using your positioning function
    	
	
  
	    // Use the .exit() and .remove() methods to remove elements that are no longer in the data
		
	  
	    // Select all circle elements within your g and transition their position using your positioning function
		

	
	}

Answer time

# Checkout a new branch 'exercise-clean' from the remote branch
git checkout -b exercise-complete remotes/origin/exercise-complete

Sync repo

# Adds a new remote 'upstream', indicating repo source
git remote add upstream https://github.com/mkfreeman/d3-demo.git

# Fetch any changes from the upstream repo
git fetch upstream

# Checkout a new branch "angular-exercise" from my "angular-clean" branch
git checkout -b angular-exercise remotes/upstream/angular-clean

Our App

var myApp = angular.module("myApp", ['ui.bootstrap'])

// Bind controller and set $scope.data as your data variable
myApp.controller('myCtrl', function($scope){
	$scope.data = data;
})


// Create a directive 'scatter' that creates scatterplots, and takes in $filter and $compile
myApp.directive('scatter', function($filter, $compile){

    // we'll write some code in here....

})

HTML Set-up

<!-- Create a scatter directive that 
takes in data and search as attributes -->

<!-- Container for your elements -->
<div class="container" id="vis">
    <input placeholder="search country or region" class="form-control" ng-model="search" />	

    <!-- This is where your chart goes! -->
			
</div>

Passing in data

return {
    restrict:'E', // this directive is specified as an html element <scatter>

    // Define variables 'data' and 'search' as variables you've passed into HTML
    scope:{
			

    },

    // Create a link function that allows dynamic element creation

    link:

Manipulating HTML

// Create a link function that allows dynamic element creation

link:function(scope,elem,attrs){
    // Create a variable wrapper by making a 
    // d3 selection the HTML element elem[0]


    // Use the scope.$watch method to watch for 
    // changes to 'search', and executes your draw function



    // Copy and paste code from your_scatter_code.js into here
}

Changes to d3 code

// Create a variable scope.filteredData using 
// $filter to narrow down your data based on your search

Creating hovers

var circleFunc = function(circle) {
	circle.attr('r', 10)

	// Add a tooltip-append-to-body attribute, set it to true
	// Add a tooltip property that has the content you want in your tooltip					
}	

...........

var draw = function() {

    ......

    circles.enter().append('circle')
    // Compile entering nodes so that tooltip attribute is activated
    .call(function(){
         $compile(this[0].parentNode)(scope);
    })

}

Assignment

Personal portfolio (due next week)

angular-d3

By Michael Freeman

angular-d3

  • 1,586