Skip to content

Commit 106e52c

Browse files
committed
Merge pull request #492 from plotly/winkel-tripel
Add support for Winkel Tripel projection
2 parents dca69f9 + 515f2fb commit 106e52c

File tree

14 files changed

+5684
-23
lines changed

14 files changed

+5684
-23
lines changed

.eslintignore

-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ build
44

55
test/jasmine/assets/jquery-1.8.3.min.js
66
src/plots/polar/micropolar.js
7-
src/plots/geo/projections.js

src/constants/geo_constants.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ params.projNames = {
3232
'mollweide': 'mollweide',
3333
'hammer': 'hammer',
3434
'transverse mercator': 'transverseMercator',
35-
'albers usa': 'albersUsa'
35+
'albers usa': 'albersUsa',
36+
'winkel tripel': 'winkel3'
3637
};
3738

3839
// name of the axes

src/lib/topojson_utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
var topojsonUtils = module.exports = {};
1313

14-
var locationmodeToLayer = require('../constants/geo_constants').locationmodeToLayer,
14+
var locationmodeToLayer = require('../plots/geo/constants').locationmodeToLayer,
1515
topojsonFeature = require('topojson').feature;
1616

1717

src/plots/geo/constants.js

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var params = module.exports = {};
13+
14+
// projection names to d3 function name
15+
params.projNames = {
16+
// d3.geo.projection
17+
'equirectangular': 'equirectangular',
18+
'mercator': 'mercator',
19+
'orthographic': 'orthographic',
20+
'natural earth': 'naturalEarth',
21+
'kavrayskiy7': 'kavrayskiy7',
22+
'miller': 'miller',
23+
'robinson': 'robinson',
24+
'eckert4': 'eckert4',
25+
'azimuthal equal area': 'azimuthalEqualArea',
26+
'azimuthal equidistant': 'azimuthalEquidistant',
27+
'conic equal area': 'conicEqualArea',
28+
'conic conformal': 'conicConformal',
29+
'conic equidistant': 'conicEquidistant',
30+
'gnomonic': 'gnomonic',
31+
'stereographic': 'stereographic',
32+
'mollweide': 'mollweide',
33+
'hammer': 'hammer',
34+
'transverse mercator': 'transverseMercator',
35+
'albers usa': 'albersUsa',
36+
'winkel tripel': 'winkel3'
37+
};
38+
39+
// name of the axes
40+
params.axesNames = ['lonaxis', 'lataxis'];
41+
42+
// max longitudinal angular span (EXPERIMENTAL)
43+
params.lonaxisSpan = {
44+
'orthographic': 180,
45+
'azimuthal equal area': 360,
46+
'azimuthal equidistant': 360,
47+
'conic conformal': 180,
48+
'gnomonic': 160,
49+
'stereographic': 180,
50+
'transverse mercator': 180,
51+
'*': 360
52+
};
53+
54+
// max latitudinal angular span (EXPERIMENTAL)
55+
params.lataxisSpan = {
56+
'conic conformal': 150,
57+
'stereographic': 179.5,
58+
'*': 180
59+
};
60+
61+
// defaults for each scope
62+
params.scopeDefaults = {
63+
world: {
64+
lonaxisRange: [-180, 180],
65+
lataxisRange: [-90, 90],
66+
projType: 'equirectangular',
67+
projRotate: [0, 0, 0]
68+
},
69+
usa: {
70+
lonaxisRange: [-180, -50],
71+
lataxisRange: [15, 80],
72+
projType: 'albers usa'
73+
},
74+
europe: {
75+
lonaxisRange: [-30, 60],
76+
lataxisRange: [30, 80],
77+
projType: 'conic conformal',
78+
projRotate: [15, 0, 0],
79+
projParallels: [0, 60]
80+
},
81+
asia: {
82+
lonaxisRange: [22, 160],
83+
lataxisRange: [-15, 55],
84+
projType: 'mercator',
85+
projRotate: [0, 0, 0]
86+
},
87+
africa: {
88+
lonaxisRange: [-30, 60],
89+
lataxisRange: [-40, 40],
90+
projType: 'mercator',
91+
projRotate: [0, 0, 0]
92+
},
93+
'north america': {
94+
lonaxisRange: [-180, -45],
95+
lataxisRange: [5, 85],
96+
projType: 'conic conformal',
97+
projRotate: [-100, 0, 0],
98+
projParallels: [29.5, 45.5]
99+
},
100+
'south america': {
101+
lonaxisRange: [-100, -30],
102+
lataxisRange: [-60, 15],
103+
projType: 'mercator',
104+
projRotate: [0, 0, 0]
105+
}
106+
};
107+
108+
// angular pad to avoid rounding error around clip angles
109+
params.clipPad = 1e-3;
110+
111+
// map projection precision
112+
params.precision = 0.1;
113+
114+
// default land and water fill colors
115+
params.landColor = '#F0DC82';
116+
params.waterColor = '#3399FF';
117+
118+
// locationmode to layer name
119+
params.locationmodeToLayer = {
120+
'ISO-3': 'countries',
121+
'USA-states': 'subunits',
122+
'country names': 'countries'
123+
};
124+
125+
// SVG element for a sphere (use to frame maps)
126+
params.sphereSVG = {type: 'Sphere'};
127+
128+
// N.B. base layer names must be the same as in the topojson files
129+
130+
// base layer with a fill color
131+
params.fillLayers = ['ocean', 'land', 'lakes'];
132+
133+
// base layer with a only a line color
134+
params.lineLayers = ['subunits', 'countries', 'coastlines', 'rivers', 'frame'];
135+
136+
// all base layers - in order
137+
params.baseLayers = [
138+
'ocean', 'land', 'lakes',
139+
'subunits', 'countries', 'coastlines', 'rivers',
140+
'lataxis', 'lonaxis',
141+
'frame'
142+
];
143+
144+
params.layerNameToAdjective = {
145+
ocean: 'ocean',
146+
land: 'land',
147+
lakes: 'lake',
148+
subunits: 'subunit',
149+
countries: 'country',
150+
coastlines: 'coastline',
151+
rivers: 'river',
152+
frame: 'frame'
153+
};
154+
155+
// base layers drawn over choropleth
156+
params.baseLayersOverChoropleth = ['rivers', 'lakes'];

src/plots/geo/geo.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ var addProjectionsToD3 = require('./projections');
2323
var createGeoScale = require('./set_scale');
2424
var createGeoZoom = require('./zoom');
2525
var createGeoZoomReset = require('./zoom_reset');
26+
var constants = require('./constants');
2627

2728
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
28-
var constants = require('../../constants/geo_constants');
2929
var topojsonUtils = require('../../lib/topojson_utils');
3030
var topojsonFeature = require('topojson').feature;
3131

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

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

4443
this.hoverContainer = null;
4544

src/plots/geo/layout/axis_defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
'use strict';
1111

1212
var Lib = require('../../../lib');
13-
var constants = require('../../../constants/geo_constants');
13+
var constants = require('../constants');
1414
var axisAttributes = require('./axis_attributes');
1515

1616

src/plots/geo/layout/defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
'use strict';
1111

1212
var handleSubplotDefaults = require('../../subplot_defaults');
13-
var constants = require('../../../constants/geo_constants');
13+
var constants = require('../constants');
1414
var layoutAttributes = require('./layout_attributes');
1515
var supplyGeoAxisLayoutDefaults = require('./axis_defaults');
1616

src/plots/geo/layout/layout_attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
'use strict';
1010

1111
var colorAttrs = require('../../../components/color/attributes');
12-
var constants = require('../../../constants/geo_constants');
12+
var constants = require('../constants');
1313
var geoAxesAttrs = require('./axis_attributes');
1414

1515

src/plots/geo/projections.js

+44-10
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
/**
10-
* Forked from https://github.com/d3/d3-geo-projection
11-
* Pasted from https://github.com/etpinard/d3-geo-projection
9+
/*
10+
* Generated by https://github.com/etpinard/d3-geo-projection-picker
1211
*
13-
* Containing only the 'most useful' projection types
14-
* and compatible with CommonJs
12+
* which is hand-picks projection from https://github.com/d3/d3-geo-projection
1513
*
14+
* into a CommonJS require-able module.
1615
*/
1716

18-
var d3 = require('d3');
17+
'use strict';
18+
19+
/* eslint-disable */
1920

20-
function addProjectionToD3() {
21+
function addProjectionsToD3(d3) {
2122
d3.geo.project = function(object, projection) {
2223
var stream = projection.stream;
2324
if (!stream) throw new Error("not yet supported");
@@ -78,7 +79,7 @@ function addProjectionToD3() {
7879
d3_geo_projectPoints.push([ x, y ]);
7980
},
8081
lineEnd: function() {
81-
if (d3_geo_projectPoints.length) d3_geo_projectLines.push(d3_geo_projectPoints),
82+
if (d3_geo_projectPoints.length) d3_geo_projectLines.push(d3_geo_projectPoints),
8283
d3_geo_projectPoints = [];
8384
},
8485
result: function() {
@@ -205,7 +206,7 @@ function addProjectionToD3() {
205206
};
206207
var projection = d3.geo.projection(forward), stream_ = projection.stream;
207208
projection.stream = function(stream) {
208-
var rotate = projection.rotate(), rotateStream = stream_(stream), sphereStream = (projection.rotate([ 0, 0 ]),
209+
var rotate = projection.rotate(), rotateStream = stream_(stream), sphereStream = (projection.rotate([ 0, 0 ]),
209210
stream_(stream));
210211
projection.rotate(rotate);
211212
rotateStream.sphere = function() {
@@ -405,6 +406,39 @@ function addProjectionToD3() {
405406
(d3.geo.sinusoidal = function() {
406407
return projection(sinusoidal);
407408
}).raw = sinusoidal;
409+
function aitoff(λ, φ) {
410+
var cosφ = Math.cos(φ), sinciα = sinci(acos(cosφ * Math.cos(λ /= 2)));
411+
return [ 2 * cosφ * Math.sin(λ) * sinciα, Math.sin(φ) * sinciα ];
412+
}
413+
aitoff.invert = function(x, y) {
414+
if (x * x + 4 * y * y > π * π + ε) return;
415+
var λ = x, φ = y, i = 25;
416+
do {
417+
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δλ;
418+
if (!denominator) break;
419+
var δλ = (fy * δxδφ - fx * δyδφ) / denominator, δφ = (fx * δyδλ - fy * δxδλ) / denominator;
420+
λ -= δλ, φ -= δφ;
421+
} while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0);
422+
return [ λ, φ ];
423+
};
424+
(d3.geo.aitoff = function() {
425+
return projection(aitoff);
426+
}).raw = aitoff;
427+
function winkel3(λ, φ) {
428+
var coordinates = aitoff(λ, φ);
429+
return [ (coordinates[0] + λ / halfπ) / 2, (coordinates[1] + φ) / 2 ];
430+
}
431+
winkel3.invert = function(x, y) {
432+
var λ = x, φ = y, i = 25;
433+
do {
434+
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;
435+
λ -= δλ, φ -= δφ;
436+
} while ((Math.abs(δλ) > ε || Math.abs(δφ) > ε) && --i > 0);
437+
return [ λ, φ ];
438+
};
439+
(d3.geo.winkel3 = function() {
440+
return projection(winkel3);
441+
}).raw = winkel3;
408442
}
409443

410-
module.exports = addProjectionToD3;
444+
module.exports = addProjectionsToD3;

src/plots/geo/set_scale.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
var d3 = require('d3');
1313

14-
var clipPad = require('../../constants/geo_constants').clipPad;
14+
var clipPad = require('./constants/').clipPad;
1515

1616
function createGeoScale(geoLayout, graphSize) {
1717
var projLayout = geoLayout.projection,

src/traces/choropleth/plot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeature
2222
var locationToFeature = require('../../lib/geo_location_utils').locationToFeature;
2323
var arrayToCalcItem = require('../../lib/array_to_calc_item');
2424

25-
var constants = require('../../constants/geo_constants');
25+
var constants = require('../../plots/geo/constants');
2626
var attributes = require('./attributes');
2727

2828
var plotChoropleth = module.exports = {};
212 KB
Loading

0 commit comments

Comments
 (0)