Skip to content

Add support for Winkel Tripel projection #492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ build

test/jasmine/assets/jquery-1.8.3.min.js
src/plots/polar/micropolar.js
src/plots/geo/projections.js
3 changes: 2 additions & 1 deletion src/constants/geo_constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ params.projNames = {
'mollweide': 'mollweide',
'hammer': 'hammer',
'transverse mercator': 'transverseMercator',
'albers usa': 'albersUsa'
'albers usa': 'albersUsa',
'winkel tripel': 'winkel3'
};

// name of the axes
Expand Down
2 changes: 1 addition & 1 deletion src/lib/topojson_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

var topojsonUtils = module.exports = {};

var locationmodeToLayer = require('../constants/geo_constants').locationmodeToLayer,
var locationmodeToLayer = require('../plots/geo/constants').locationmodeToLayer,
topojsonFeature = require('topojson').feature;


Expand Down
156 changes: 156 additions & 0 deletions src/plots/geo/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var params = module.exports = {};

// projection names to d3 function name
params.projNames = {
// d3.geo.projection
'equirectangular': 'equirectangular',
'mercator': 'mercator',
'orthographic': 'orthographic',
'natural earth': 'naturalEarth',
'kavrayskiy7': 'kavrayskiy7',
'miller': 'miller',
'robinson': 'robinson',
'eckert4': 'eckert4',
'azimuthal equal area': 'azimuthalEqualArea',
'azimuthal equidistant': 'azimuthalEquidistant',
'conic equal area': 'conicEqualArea',
'conic conformal': 'conicConformal',
'conic equidistant': 'conicEquidistant',
'gnomonic': 'gnomonic',
'stereographic': 'stereographic',
'mollweide': 'mollweide',
'hammer': 'hammer',
'transverse mercator': 'transverseMercator',
'albers usa': 'albersUsa',
'winkel tripel': 'winkel3'
};

// name of the axes
params.axesNames = ['lonaxis', 'lataxis'];

// max longitudinal angular span (EXPERIMENTAL)
params.lonaxisSpan = {
'orthographic': 180,
'azimuthal equal area': 360,
'azimuthal equidistant': 360,
'conic conformal': 180,
'gnomonic': 160,
'stereographic': 180,
'transverse mercator': 180,
'*': 360
};

// max latitudinal angular span (EXPERIMENTAL)
params.lataxisSpan = {
'conic conformal': 150,
'stereographic': 179.5,
'*': 180
};

// defaults for each scope
params.scopeDefaults = {
world: {
lonaxisRange: [-180, 180],
lataxisRange: [-90, 90],
projType: 'equirectangular',
projRotate: [0, 0, 0]
},
usa: {
lonaxisRange: [-180, -50],
lataxisRange: [15, 80],
projType: 'albers usa'
},
europe: {
lonaxisRange: [-30, 60],
lataxisRange: [30, 80],
projType: 'conic conformal',
projRotate: [15, 0, 0],
projParallels: [0, 60]
},
asia: {
lonaxisRange: [22, 160],
lataxisRange: [-15, 55],
projType: 'mercator',
projRotate: [0, 0, 0]
},
africa: {
lonaxisRange: [-30, 60],
lataxisRange: [-40, 40],
projType: 'mercator',
projRotate: [0, 0, 0]
},
'north america': {
lonaxisRange: [-180, -45],
lataxisRange: [5, 85],
projType: 'conic conformal',
projRotate: [-100, 0, 0],
projParallels: [29.5, 45.5]
},
'south america': {
lonaxisRange: [-100, -30],
lataxisRange: [-60, 15],
projType: 'mercator',
projRotate: [0, 0, 0]
}
};

// angular pad to avoid rounding error around clip angles
params.clipPad = 1e-3;

// map projection precision
params.precision = 0.1;

// default land and water fill colors
params.landColor = '#F0DC82';
params.waterColor = '#3399FF';

// locationmode to layer name
params.locationmodeToLayer = {
'ISO-3': 'countries',
'USA-states': 'subunits',
'country names': 'countries'
};

// SVG element for a sphere (use to frame maps)
params.sphereSVG = {type: 'Sphere'};

// N.B. base layer names must be the same as in the topojson files

// base layer with a fill color
params.fillLayers = ['ocean', 'land', 'lakes'];

// base layer with a only a line color
params.lineLayers = ['subunits', 'countries', 'coastlines', 'rivers', 'frame'];

// all base layers - in order
params.baseLayers = [
'ocean', 'land', 'lakes',
'subunits', 'countries', 'coastlines', 'rivers',
'lataxis', 'lonaxis',
'frame'
];

params.layerNameToAdjective = {
ocean: 'ocean',
land: 'land',
lakes: 'lake',
subunits: 'subunit',
countries: 'country',
coastlines: 'coastline',
rivers: 'river',
frame: 'frame'
};

// base layers drawn over choropleth
params.baseLayersOverChoropleth = ['rivers', 'lakes'];
7 changes: 3 additions & 4 deletions src/plots/geo/geo.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ var addProjectionsToD3 = require('./projections');
var createGeoScale = require('./set_scale');
var createGeoZoom = require('./zoom');
var createGeoZoomReset = require('./zoom_reset');
var constants = require('./constants');

var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
var constants = require('../../constants/geo_constants');
var topojsonUtils = require('../../lib/topojson_utils');
var topojsonFeature = require('topojson').feature;

Expand All @@ -37,9 +37,8 @@ function Geo(options, fullLayout) {
this.container = options.container;
this.topojsonURL = options.topojsonURL;

// add a few projection types to d3.geo,
// a subset of https://github.com/d3/d3-geo-projection
addProjectionsToD3();
// add a few projection types to d3.geo
addProjectionsToD3(d3);

this.hoverContainer = null;

Expand Down
2 changes: 1 addition & 1 deletion src/plots/geo/layout/axis_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

var Lib = require('../../../lib');
var constants = require('../../../constants/geo_constants');
var constants = require('../constants');
var axisAttributes = require('./axis_attributes');


Expand Down
2 changes: 1 addition & 1 deletion src/plots/geo/layout/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

var handleSubplotDefaults = require('../../subplot_defaults');
var constants = require('../../../constants/geo_constants');
var constants = require('../constants');
var layoutAttributes = require('./layout_attributes');
var supplyGeoAxisLayoutDefaults = require('./axis_defaults');

Expand Down
2 changes: 1 addition & 1 deletion src/plots/geo/layout/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
'use strict';

var colorAttrs = require('../../../components/color/attributes');
var constants = require('../../../constants/geo_constants');
var constants = require('../constants');
var geoAxesAttrs = require('./axis_attributes');


Expand Down
54 changes: 44 additions & 10 deletions src/plots/geo/projections.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@
* LICENSE file in the root directory of this source tree.
*/

/**
* Forked from https://github.com/d3/d3-geo-projection
* Pasted from https://github.com/etpinard/d3-geo-projection
/*
* Generated by https://github.com/etpinard/d3-geo-projection-picker
*
* Containing only the 'most useful' projection types
* and compatible with CommonJs
* which is hand-picks projection from https://github.com/d3/d3-geo-projection
*
* into a CommonJS require-able module.
*/

var d3 = require('d3');
'use strict';

/* eslint-disable */

function addProjectionToD3() {
function addProjectionsToD3(d3) {
d3.geo.project = function(object, projection) {
var stream = projection.stream;
if (!stream) throw new Error("not yet supported");
Expand Down Expand Up @@ -78,7 +79,7 @@ function addProjectionToD3() {
d3_geo_projectPoints.push([ x, y ]);
},
lineEnd: function() {
if (d3_geo_projectPoints.length) d3_geo_projectLines.push(d3_geo_projectPoints),
if (d3_geo_projectPoints.length) d3_geo_projectLines.push(d3_geo_projectPoints),
d3_geo_projectPoints = [];
},
result: function() {
Expand Down Expand Up @@ -205,7 +206,7 @@ function addProjectionToD3() {
};
var projection = d3.geo.projection(forward), stream_ = projection.stream;
projection.stream = function(stream) {
var rotate = projection.rotate(), rotateStream = stream_(stream), sphereStream = (projection.rotate([ 0, 0 ]),
var rotate = projection.rotate(), rotateStream = stream_(stream), sphereStream = (projection.rotate([ 0, 0 ]),
stream_(stream));
projection.rotate(rotate);
rotateStream.sphere = function() {
Expand Down Expand Up @@ -405,6 +406,39 @@ function addProjectionToD3() {
(d3.geo.sinusoidal = function() {
return projection(sinusoidal);
}).raw = sinusoidal;
function aitoff(λ, φ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhhh...

var cosφ = Math.cos(φ), sinciα = sinci(acos(cosφ * Math.cos(λ /= 2)));
return [ 2 * cosφ * Math.sin(λ) * sinciα, Math.sin(φ) * sinciα ];
}
aitoff.invert = function(x, y) {
if (x * x + 4 * y * y > π * π + ε) return;
var λ = x, φ = y, i = 25;
do {
var sinλ = Math.sin(λ), sinλ_2 = Math.sin(λ / 2), cosλ_2 = Math.cos(λ / 2), sinφ = Math.sin(φ), cosφ = Math.cos(φ), sin_2φ = Math.sin(2 * φ), sin2φ = sinφ * sinφ, cos2φ = cosφ * cosφ, sin2λ_2 = sinλ_2 * sinλ_2, C = 1 - cos2φ * cosλ_2 * cosλ_2, E = C ? acos(cosφ * cosλ_2) * Math.sqrt(F = 1 / C) : F = 0, F, fx = 2 * E * cosφ * sinλ_2 - x, fy = E * sinφ - y, δxδλ = F * (cos2φ * sin2λ_2 + E * cosφ * cosλ_2 * sin2φ), δxδφ = F * (.5 * sinλ * sin_2φ - E * 2 * sinφ * sinλ_2), δyδλ = F * .25 * (sin_2φ * sinλ_2 - E * sinφ * cos2φ * sinλ), δyδφ = F * (sin2φ * cosλ_2 + E * sin2λ_2 * cosφ), denominator = δxδφ * δyδλ - δyδφ * δxδλ;
if (!denominator) break;
var δλ = (fy * δxδφ - fx * δyδφ) / denominator, δφ = (fx * δyδλ - fy * δxδλ) / denominator;
λ -= δλ, φ -= δφ;
} while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0);
return [ λ, φ ];
};
(d3.geo.aitoff = function() {
return projection(aitoff);
}).raw = aitoff;
function winkel3(λ, φ) {
var coordinates = aitoff(λ, φ);
return [ (coordinates[0] + λ / halfπ) / 2, (coordinates[1] + φ) / 2 ];
}
winkel3.invert = function(x, y) {
var λ = x, φ = y, i = 25;
do {
var cosφ = Math.cos(φ), sinφ = Math.sin(φ), sin_2φ = Math.sin(2 * φ), sin2φ = sinφ * sinφ, cos2φ = cosφ * cosφ, sinλ = Math.sin(λ), cosλ_2 = Math.cos(λ / 2), sinλ_2 = Math.sin(λ / 2), sin2λ_2 = sinλ_2 * sinλ_2, C = 1 - cos2φ * cosλ_2 * cosλ_2, E = C ? acos(cosφ * cosλ_2) * Math.sqrt(F = 1 / C) : F = 0, F, fx = .5 * (2 * E * cosφ * sinλ_2 + λ / halfπ) - x, fy = .5 * (E * sinφ + φ) - y, δxδλ = .5 * F * (cos2φ * sin2λ_2 + E * cosφ * cosλ_2 * sin2φ) + .5 / halfπ, δxδφ = F * (sinλ * sin_2φ / 4 - E * sinφ * sinλ_2), δyδλ = .125 * F * (sin_2φ * sinλ_2 - E * sinφ * cos2φ * sinλ), δyδφ = .5 * F * (sin2φ * cosλ_2 + E * sin2λ_2 * cosφ) + .5, denominator = δxδφ * δyδλ - δyδφ * δxδλ, δλ = (fy * δxδφ - fx * δyδφ) / denominator, δφ = (fx * δyδλ - fy * δxδλ) / denominator;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wat even.

λ -= δλ, φ -= δφ;
} while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0);
return [ λ, φ ];
};
(d3.geo.winkel3 = function() {
return projection(winkel3);
}).raw = winkel3;
}

module.exports = addProjectionToD3;
module.exports = addProjectionsToD3;
2 changes: 1 addition & 1 deletion src/plots/geo/set_scale.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

var d3 = require('d3');

var clipPad = require('../../constants/geo_constants').clipPad;
var clipPad = require('./constants/').clipPad;

function createGeoScale(geoLayout, graphSize) {
var projLayout = geoLayout.projection,
Expand Down
2 changes: 1 addition & 1 deletion src/traces/choropleth/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeature
var locationToFeature = require('../../lib/geo_location_utils').locationToFeature;
var arrayToCalcItem = require('../../lib/array_to_calc_item');

var constants = require('../../constants/geo_constants');
var constants = require('../../plots/geo/constants');
var attributes = require('./attributes');

var plotChoropleth = module.exports = {};
Expand Down
Binary file added test/image/baselines/geo_winkel-tripel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading