blob: b7e4bab22cb38c65a461b73313254cda96800e7f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
/*global topojson:false */
rwt.chart.register( "topojson-world", function( widget ) {
var _dataPath;
var _width;
var _height;
var _world;
var _path;
var _showGraticule;
var _toolTip;
var _scaleFactor = 1;
var _center = [ 0, 0 ];
var _countries = {};
var _colors = [];
var chart = function( svg, widget ) {
if( !_world ) {
if( _dataPath ) {
createToolTip( widget._element );
load( svg );
}
} else {
update( svg );
}
};
chart.dataPath = function( path ) {
_dataPath = path;
return chart;
};
chart.width = function( width ) {
_width = width;
return chart;
};
chart.height = function( height ) {
_height = height;
return chart;
};
chart.countries = function( countries ) {
_countries = countries;
return chart;
};
chart.colors = function( colors ) {
_colors = colors;
return chart;
};
chart.showGraticule = function( show ) {
_showGraticule = show;
return chart;
};
chart.scaleFactor = function( factor ) {
_scaleFactor = factor;
return chart;
};
chart.center = function( center ) {
_center = center;
return chart;
};
function createToolTip( parentElement ) {
if( !_toolTip ) {
_toolTip = d3.select( parentElement ).append( "div" ).attr( "class", "tooltip hidden" );
}
}
function load( svg ) {
d3.json( _dataPath, function( error, world ) {
if( error ) {
throw error;
}
_world = world;
update( svg );
});
}
function update( svg ) {
var countries = topojson.feature( _world, _world.objects.countries );
calculateColorIndices( countries.features );
updateProjection( countries );
updateGraticule( svg );
svg.selectAll( ".country" )
.data( countries.features )
.enter()
.insert( "path", ".graticule" )
.attr( "class", "country" )
.attr( "id", function( d ) { return d.id; } )
.on( "click", function( d ) {
widget.notifySelection( d.id, 0, d.properties.code3 );
})
.on( "mouseover", function( d ) {
if( getCountryData( d ) ) {
var text = rwt.util.Encoding.escapeText( getCountryData( d ).label );
text = rwt.util.Encoding.replaceNewLines( text, "<br/>" );
_toolTip.classed( "hidden", false ).html( text );
}
})
.on( "mouseout", function() {
_toolTip.classed( "hidden", true );
})
.on( "mousemove", function( d ) {
if( getCountryData( d ) ) {
var mouse = d3.mouse( svg.node() ).map( function( d ) { return parseInt( d ); } );
var left = mouse[ 0 ] + 10;
var top = mouse[ 1 ] + 15;
_toolTip.attr( "style", "left:" + left + "px;top:" + top + "px;" );
}
});
svg.selectAll( ".country" )
.attr( "d", _path )
.style( "fill", fill );
}
function updateProjection( countries ) {
var scale = 150;
var offset = [ _width / 2, _height / 2 ];
var projection = d3.geo.equirectangular()
.scale( scale )
.translate( offset )
.precision( 0.1 );
_path = d3.geo.path().projection( projection );
var bounds = _path.bounds( countries );
var hscale = scale * _width / ( bounds[ 1 ][ 0 ] - bounds[ 0 ][ 0 ] );
var vscale = scale * _height / ( bounds[ 1 ][ 1 ] - bounds[ 0 ][ 1 ] );
scale = ( hscale < vscale ) ? hscale : vscale;
projection = d3.geo.equirectangular()
.scale( scale * _scaleFactor )
.translate( offset )
.precision( 0.1 )
.center( _center );
_path = _path.projection( projection );
}
function updateGraticule( svg ) {
if( _showGraticule ) {
if( svg.selectAll( ".graticule" ).size() === 0 ) {
var graticule = d3.geo.graticule();
svg.append( "path" )
.datum( graticule )
.attr( "class", "graticule" );
svg.append( "path" )
.datum( graticule.outline )
.attr( "class", "graticule outline" );
}
svg.selectAll( ".graticule" ).attr( "d", _path );
} else {
svg.selectAll( ".graticule" ).remove();
}
}
function fill( d ) {
if( getCountryData( d ) ) {
return getCountryData( d ).color;
}
return _colors[ d.col % _colors.length ];
}
function calculateColorIndices( countries ) {
var neighbors = topojson.neighbors( _world.objects.countries.geometries );
countries.forEach( function( d, i ) {
var getCol = function( n ) {
return countries[ n ].col;
};
d.col = d3.max( neighbors[ i ], getCol ) + 1 | 0;
});
}
function getCountryData( d ) {
var props = d.properties;
return _countries[ d.id ] || _countries[ props.code2 ] || _countries[ props.code3 ];
}
widget._scheduleUpdate();
return chart;
});