// create a map
var data, // GeoJSON data of voting districts
selection, // reference to current selection highlight
map = $( "#map" ).geomap( {
center: [ -71.0595678, 42.3604823 ],
zoom: 8,
click: function( e, geo ) {
// remove any previous selection graphic
if ( selection ) {
map.geomap( "remove", selection );
}
// find a voting district at the clicked location
var district = map.geomap( "find", geo, 1 );
if ( district.length > 0 ) {
// make a copy of the feature for selection highlight
selection = $.extend( true, { }, district[ 0 ] );
// display some info about the voting district
$( "[data-text='Name']" ).text( selection.properties.Name );
var $descTable = $( selection.properties.Description );
$descTable.find( "tr:eq(5)" ).remove( );
$descTable.find( "tr:eq(4) td:first-child" ).text( "Hispanic Origin" );
$( "[data-html='Description']" ).empty().append( $descTable ).show();
// set the map's bbox to the bbox of the feature
// but scale the bbox by 2x first to zoom out a little
map.geomap( "option", "bbox", $.geo.scaleBy( $.geo.bbox( selection ), 2 ) );
// append the selection highlight shape with a thick red border
map.geomap( "append", selection, { opacity: 1, fillOpacity: 0, color: "red", strokeWidth: "4px" } );
}
}
} );
// set an initial shapeStyle for the demographic display, all white, no border
map.geomap( "option", "shapeStyle", { strokeWidth: "0px", opacity: 1, color: "#fff" } );
// jQuery UI for pretty sliders
$( "#sliderBasemap" ).slider( {
value: 100,
slide: function ( e, ui ) {
// when the basemap slider slides,
// set the new opacity on the osm layer
// you can target specific layers with jQuery selector syntax
// the default service object has a css class of osm
$( "#map .osm" ).geomap( "opacity", ui.value / 100 );
}
} );
$( ".slider" ).slider( {
value: 100,
change: function( e, ui ) {
// when any demographic slider changes, get all the values
var red = $( "#sliderR" ).slider( "option", "value" ),
green = $( "#sliderG" ).slider( "option", "value" ),
blue = $( "#sliderB" ).slider( "option", "value" ),
alpha = $( "#sliderA" ).slider( "option", "value" );
// set the shapeStyle to the new color and global opacity
// since each individual shape only overrides fillOpacity,
// this single call will modify all shapes without having to re-append them
map.geomap( "option", "shapeStyle", {
color: "rgb( " + Math.floor( 255 * red / 100 ) + ", " + Math.floor( 255 * green / 100 ) + ", " + Math.floor( 255 * blue / 100 ) + " )",
opacity: alpha / 100
} , false );
}
} );
// jQuery UI for pretty radio buttons
$( "#demographic" ).buttonset( );
$( "#demographic input" ).click( function( ) {
// when a demographic radio button changes,
// generate new demographic shapes from the existing data
showData( data, $(this).val() );
} );
// download the voting district shapes and demographics
$.ajax( {
url: "http://data.jquerygeo.com/ma-voting-districts.geojson",
dataType: "json",
success: function( result ) {
// save a copy
data = result;
// generate new demographic shapes based on whichever input is checked
showData( data, $( "#demographic input:checked" ).val( ) );
$( "#demographic img" ).remove();
},
error: function( xhr ) {
// uh oh
alert( xhr.statusText );
}
} );
function showData( data, demoIndex ) {
// clear any existing demographic shapes
map.geomap( "empty" );
if ( data && data.type == "FeatureCollection" ) {
$.each( data.features, function( ) {
// for each voting district, extract the requested demographic row, demoIndex
// and compare it to the total population row, 0
var infoTable = $( this.properties.Description ),
pop = parseInt( infoTable.find( "tr:eq(0) td:eq(1)" ).text() ),
demo = parseInt( infoTable.find( "tr:eq(" + demoIndex + ") td:eq(1)" ).text() ),
pct = demo / pop;
// append a shape for the voting district,
// its fillOpacity is set to the demographic's relationship to total population
// for performance, don't refresh while adding these, that ending false
map.geomap( "append", this, { fillOpacity: 1 - pct } , false );
} );
if ( selection ) {
// if there's an existing selection highlight shape,
// append it with a thick red border
map.geomap( "append", selection, { opacity: 1, fillOpacity: 0, color: "red", strokeWidth: "4px" }, false );
}
// refresh the map after appending all the new shapes
map.geomap( "refresh" );
}
}
<div id="map">
</div>
<div class="info">
<div id="sliders">
<fieldset>
<legend>basemap transparency</legend>
<div id="sliderBasemap"></div>
</fieldset>
<fieldset>
<legend>demographic color</legend>
<div>
<label>red</label> <div id="sliderR" class="slider"></div>
<label>green</label> <div id="sliderG" class="slider"></div>
<label>blue</label> <div id="sliderB" class="slider"></div>
<label>transparency</label> <div id="sliderA" class="slider"></div>
</div>
</fieldset>
</div>
<h1>Voting Districts by %</h1>
<div id="demographic">
<input type="radio" id="optWhite" name="demographic" value="1" checked /><label for="optWhite">White</label>
<input type="radio" id="optBlack" name="demographic" value="2" /><label for="optBlack">Black</label>
<input type="radio" id="optAsian" name="demographic" value="3" /><label for="optAsian">Asian</label>
<input type="radio" id="optHispanic" name="demographic" value="4" /><label for="optHispanic">Hispanic</label>
</div>
<h2 data-text="Name"></h2>
<div data-html="Description" style="display: none;">
</div>
</div>
html
{
font:13px/1.231 Calibri,Arial,sans-serif; *font-size:small;
}
.info
{
background: #fff;
border-radius: 8px;
box-shadow: -4px 4px #444;
opacity: .8;
padding: 8px;
width: 95%;
}
#map
{
background: #fff;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
#sliders
{
margin-top: 32px;
}
.slider
{
margin: 8px;
}
h1, #demographic { display: inline-block; }
td:first-child { font-weight: bold }
External resources loaded into this fiddle: