Buttons and dropdowns and sliders

(oh my)

Outline

  • Reusable code
  • HTML Controls
  • jQuery
  • Defining controls
  • Event binding
  • Hover text

Reusable code

Write functions that (re)position elements on your page

  • Functions should enter, exit, and update elements
  • 
    var drawCircles = function(data) {
      // Select svg
      var mySvg = d3.select('#my-svg')
      
      // Bind data to selection of text elements
      var circles = mySvg.selectAll('circle').data(data, function(d){return d.id})
      
      // Exit data that might be missing
      circles.exit().remove()
      
      // Enter new data elements
      circles.enter().append('circle').call(positionCircles)
      
      // Transition all circle elements
      mySvg.selectAll('circle').transition().duration(500).call(positionCircles)
      
    }
    
    
  • Positioning should also rely on reusable functions
  • 
    var positionCircles = function(circ){
      circ.attr('cx', function(d){return Math.random()*100})
          .attr('cy', function(d,i) {return (d.id)*40})
          .attr('r', 15)
          .style('fill', function(d){return d.color})
    }
    

Data preparation (high level)

  • Isolating the data preparation process can improve reusability
  • Variable names should not be present in charting code
  • 
    var draw = function() {
    	prepData()
    	setScales()
    	positionElements()
    }								
    

Data preparation

  • Your raw data can be an array of objects
  • 
    var rawDraw =  {
    	{iso3: "ABW", region: "Latin America & Caribbean", ex_1960: 65.56936585, ex_1970: 69.08614634, ex_1980: 72.22014634}, 
    	{iso3: "AFG", region: "Sub-Saharan Africa", ex_1960: 31.58004878, ex_1970: 36.65943902, ex_1980: 41.23365854…}	
    }								
    
  • Write a prep data function to filter down to reusable structure
  • 
    settings = {
    	xVar:'ex_1980',
    	yVar:'ex_1990'
    }
    var prepData = function() {
    	data = rawData.map(function(d) {
    	var obj = {}
    		obj.region = d.region
    		obj.x = d[settings.xVar]
    		obj.y = d[settings.yVar]
    	return obj
    })	
    }								
    
  • Reference standard variables in your code
  • 
    var circleFunc = function(circ) {
    	circ
    	.attr('cx', function(d) {return xScale(d.x)})
      	.attr('cy', function(d) {return yScale(d.y)})
    	.attr('r', settings.radius)
    } 							
    

Example

HTML Controls

Controls consist of HTML elements

  • HTML uses a <input> tag for buttons
  • 
    <input id="button1" type="button" value="Button Text!"></input>
    
  • The "onclick" attribute indicates function that gets executed on click
  • 
    <input id="button1" type="button" value="Button Text!" onclick="alert('clicked')"></input>
    
  • Onclick functions can(should) reference your JavaScript code

HTML can also be used to make radios


<div id="sex">
    <input type="radio" id="sex1" name="sex"><label for="sex1">Males</label>
    <input type="radio" id="sex2" name="sex" checked="checked"><label for="sex2">Females</label>
    <input type="radio" id="sex3" name="sex"><label for="sex3">Both</label>
  </div>				

HTML can also be used to make select menus


 <label for="speed">Select a speed</label>
    <select name="speed" id="speed">
      <option>Slower</option>
      <option>Slow</option>
      <option selected="selected">Medium</option>
      <option>Fast</option>
      <option>Faster</option>
    </select>

jQuery

jQuery is a JavaScript library (similar to D3)

  • Select using the "$" symbol instead of "d3.select"
  • 
    d3.select('#my-svg')
    $('#my-svg')
    
  • Transforms elements into controls
  • 
    $('#my-button').buttonset()
    
  • Dynamically binding events to buttons
  • 
    $('#my-button').on('click', function() {
    	// take actions here
    })		
    

Styling is done via jQuery's UI library

  • jQuery UI is an extension fo jQuery (for UI)
  • Easily included in js.bin
  • Add library > jQuery UI 1.11.1
  • Available for download here
  • Include these files in your CSS (this include the jQuery library)
  • 
    <script src="lib/external/jquery.js"></script>
    <script src="lib/jquery-ui.js"></script>
    <link href="jquery-ui.css" rel="stylesheet">
    

Defining controls

Radio elements

  • Declare that an element is a radio using .buttonset()
  • 
    <div id="sex">
        <input type="radio" id="sex1" name="sex"><label for="sex1">Males</label>
        <input type="radio" id="sex2" name="sex" checked="checked"><label for="sex2">Females</label>
        <input type="radio" id="sex3" name="sex"><label for="sex3">Both</label>
      </div>				
    
    
    $('#sex').buttonset()				
    
  • Assigns jQuery UI defined styles
  • Allows tracking updates of state for updating

Select elements

  • Apply styles to radios using .selectmenu()
  • 
     <label for="speed">Select a speed</label>
        <select name="speed" id="speed">
          <option>Slower</option>
          <option>Slow</option>
          <option selected="selected">Medium</option>
          <option>Fast</option>
          <option>Faster</option>
        </select>
    
    
    $('#speed').selectmenu()				
    

Event binding

Event binding dictates the behavior of the page

  • Hover events
  • Click events
  • Change events
  • Can be assigned with D3 or jQuery
  • 
    $('#sex').on('change', callback)				
    $('#sex').on('click', callback)				
    $('#sex').on('hover', callback)				
    

Change events

  • You'll often want to call an event when a change occurs
  • 
    $('#sex').on('change', function() {
    	// Get value of radio
    	var sex = $('input[name="sex"]:checked').attr('id')
    	
    	// Do something about it
    	settings.sex = sex
    	draw()
    })	
    
  • Pass change events into the selectmenu() function
  • 
    $('#yvar').selectmenu({
    	change:function() {
    		
    	settings.yVar=$('#yvar').val()
    		draw()
    	}, 
    })		
    

Sliders elements

  • Transform a div into a slider using .slider()
  • 
    <div id="slider">
      </div>				
    
    
    $('#slider').slider()				
    
  • Assigns jQuery UI defined styles
  • Allows tracking updates of state for updating

Add hover text

Use the jQuery poshytip library for hovers

  • Select each path using the jQuery library
  • $('#map-svg path')
  • Call the poshytip function on selected objects ( download)
  • $('#map-svg path').poshytip({arguments})
  • Include these files
  • 
    <script src="lib/external/jquery.js"></script>
    <script src="lib/poshytip-1.2/src/jquery.poshytip.js"></script>
    <link href="lib/poshytip-1.2/src/tip-twitter/tip-twitter.css" rel="stylesheet">
    

Poshytip arguments


$('#map-svg path').poshytip({
	alignTo: 'cursor', // Align to cursor
	followCursor: true, // follow cursor when it moves
	showTimeout: 0, // No fade in
	hideTimeout: 0,  // No fade out
	alignX: 'center', // X alignment
	alignY: 'inner-bottom', // Y alignment
	className: 'tip-ihme', // Class for styling
	offsetY: 10, // Offset vertically
	slide: false, // No slide animation
	content: function(d){
		var obj = this.__data__ // Data associated with element
		var name = obj.properties.brk_name // Name from properties
		var iso3 = obj.properties.adm0_a3 // iso3
		mean = data[iso3] == undefined ? '' : data[iso3].mean // Value
		return name + ' ' + mean // String to return
	}
})

Formatting numbers

  • Use a d3.format function
  • var formatter = d3.format('.2s')
  • Pass values to your formatter variable
  • var formatted = formatter (12.234) // returns 12
  • Best understood through example