var s = .7 var width = 960*.7, height = 500*.7 var projection = d3.geo.albersUsa() .scale(1070*.7) .translate([width / 2, height / 2]); var path = d3.geo.path().projection(projection); var candidates = ['george', 'bill', 'ronald'] var color = d3.scale.category10().domain(candidates) var legend = d3.select('#left').style('width', width + 'px') .append('div.legend') .dataAppend(candidates, 'span') .text(ƒ()) .style('color', color) .on('click', function(d){ selectedCandidate = d legend.classed('selected', function(e){ return d == e }) }) legend.on('click')(candidates[0]) var svg = d3.select("#left").append('div').append("svg") .attr("width", width) .attr("height", height) var g = svg.append("g"); d3.json("us.json", function(error, us) { g.append("g") .attr("id", "states") .selectAll("path") .data(topojson.feature(us, us.objects.states).features) .enter().append("path.state") .attr("d", path) .on("click", clicked); g.append("path") .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })) .attr("id", "state-borders") .attr("d", path); window.setInterval(function(){ var initSelected = selectedCandidate var i = Math.floor(Math.random()*40) d3.selectAll('.state').each(function(d, j){ if (Math.random() > 1 || d.id > 54 || d.id == 11 || j != i) return selectedCandidate = rand(candidates) clicked(d) selectedCandidate = initSelected }) }, 1000) }); var tblHead = d3.select('#right') .style('width', 960 - width + 'px') .append('div.tbl-head') tblHead.append('div').dataAppend(['candidate', 'state'], 'div.cell') .text(ƒ()) var tbl = d3.select('#right') .style('width', 960 - width + 'px') .style('height', height + 'px') .append('div.tbl') var visits = [] function clicked(d){ d.centroid = path.centroid(d) visits.push({ place: d, candidate: selectedCandidate, state: _.findWhere(states, {id: d.id}).name, i: visits.legeth }) //offset markers on the same place d3.nest().key(ƒ('place', 'centroid')).entries(visits).forEach(function(d){ d.values.forEach(function(d, i){ d.offset = i*2 }) }) //todo - do a data join svg.selectAll('circle.visit') .data(visits).enter() .append('circle.visit') .translate(ƒ('place', 'centroid')) .attr({cx: ƒ('offset'), cy: ƒ('offset')}) .style('fill', ƒ('candidate', color)) .style('stroke', ƒ('candidate', color, darken)) .attr('r', 1) .transition() .attr('r', 10) .transition() .attr('r', 4) //update table tbl.selectAll('.row') .data(visits).enter() .insert('div.row', ":first-child") // .style('color', ƒ('color')) .selectAll('.cell') .data(function(d){ return [d.candidate, d.state] }).enter() .append('div.cell') .text(ƒ()) .style('background', 'yellow') .transition().duration(750) .style('background', 'white') // tbl.selectAll('.row').order(function(a, b){ return a.i < b.i }) } function darken(d){ return d3.rgb(d).darker(2) } function rand(array){ return array[Math.floor(Math.random()*array.length)] } var states = [ {'abv':'AL', 'fips': '01', 'name':'Alabama'}, {'abv':'AK', 'fips': '02', 'name':'Alaska'}, {'abv':'AZ', 'fips': '04', 'name':'Arizona'}, {'abv':'AR', 'fips': '05', 'name':'Arkansas'}, {'abv':'CA', 'fips': '06', 'name':'California'}, {'abv':'CO', 'fips': '08', 'name':'Colorado'}, {'abv':'CT', 'fips': '09', 'name':'Connecticut'}, {'abv':'DE', 'fips': '10', 'name':'Delaware'}, {'abv':'DC', 'fips': '11', 'name':'District of Columbia'}, {'abv':'FL', 'fips': '12', 'name':'Flordia'}, {'abv':'GA', 'fips': '13', 'name':'Georgia'}, {'abv':'HI', 'fips': '15', 'name':'Hawaii'}, {'abv':'ID', 'fips': '16', 'name':'Idaho'}, {'abv':'IL', 'fips': '17', 'name':'Illinois'}, {'abv':'IN', 'fips': '18', 'name':'Indiana'}, {'abv':'IA', 'fips': '19', 'name':'Iowa'}, {'abv':'KS', 'fips': '20', 'name':'Kansas'}, {'abv':'KY', 'fips': '21', 'name':'Kentucky'}, {'abv':'LA', 'fips': '22', 'name':'Louisiana'}, {'abv':'ME', 'fips': '23', 'name':'Maine'}, {'abv':'MD', 'fips': '24', 'name':'Maryland'}, {'abv':'MA', 'fips': '25', 'name':'Massachusetts'}, {'abv':'MI', 'fips': '26', 'name':'Michigan'}, {'abv':'MN', 'fips': '27', 'name':'Minnesota'}, {'abv':'MO', 'fips': '29', 'name':'Missouri'}, {'abv':'MS', 'fips': '28', 'name':'Mississippi'}, {'abv':'MT', 'fips': '30', 'name':'Montana'}, {'abv':'NE', 'fips': '31', 'name':'Nebraska'}, {'abv':'NV', 'fips': '32', 'name':'Nevada'}, {'abv':'NH', 'fips': '33', 'name':'New Hampshire'}, {'abv':'NJ', 'fips': '34', 'name':'New Jersey'}, {'abv':'NM', 'fips': '35', 'name':'New Mexico'}, {'abv':'NY', 'fips': '36', 'name':'New York'}, {'abv':'NC', 'fips': '37', 'name':'North Carolina'}, {'abv':'ND', 'fips': '38', 'name':'North Dakota'}, {'abv':'OH', 'fips': '39', 'name':'Ohio'}, {'abv':'OK', 'fips': '40', 'name':'Oklahoma'}, {'abv':'OR', 'fips': '41', 'name':'Oregon'}, {'abv':'PA', 'fips': '42', 'name':'Pennsylvania'}, {'abv':'RI', 'fips': '44', 'name':'Rhode Island'}, {'abv':'SC', 'fips': '45', 'name':'South Carolina'}, {'abv':'SD', 'fips': '46', 'name':'South Dakota'}, {'abv':'TN', 'fips': '47', 'name':'Tennessee'}, {'abv':'TX', 'fips': '48', 'name':'Texas'}, {'abv':'UT', 'fips': '49', 'name':'Utah'}, {'abv':'VT', 'fips': '50', 'name':'Vermont'}, {'abv':'VA', 'fips': '51', 'name':'Virginia'}, {'abv':'WA', 'fips': '53', 'name':'Washington'}, {'abv':'WV', 'fips': '54', 'name':'West Virginia'}, {'abv':'WI', 'fips': '55', 'name':'Wisconsin'}, {'abv':'WY', 'fips': '56', 'name':'Wyoming'} ]; states.forEach(function(d){ d.id = +d.fips })