1(function (root, factory) { 2 if (typeof define === 'function' && define.amd) { 3 // AMD. Register as an anonymous module. 4 define(['d3', 'topojson'], factory); 5 } else if (typeof exports === 'object') { 6 // Node. Does not work with strict CommonJS, but 7 // only CommonJS-like environments that support module.exports, 8 // like Node. 9 module.exports = factory(require('d3'), require('topojson')); 10 } else { 11 // Browser globals (root is window) 12 root.mapJustice = factory(d3, topojson); 13 } 14}(this, function (d3, topojson) { 15 'use strict'; 16 17 // colors 18 var landGray = '#C4CBCE'; 19 var countryR = 255; 20 var countryG = 255; 21 var countryB = 0; 22 23 var scale = 3; 24 var width, height, 25 land, countries, 26 context, canvas, 27 projection, translateY, path, 28 oldCountry; 29 var onReadyHighlight; 30 31 var mapJustice = { 32 ready: false, 33 reInit: function(container, newCountryCode) { 34 // If the container is not an Element terminate early 35 if (!container.tagName) { 36 console && console.error( 37 '[mapJustice] `container` is not an Element. `container`:', 38 container 39 ); 40 return; 41 } 42 43 var canvas = d3.select(container).select('canvas'); 44 if (canvas) canvas.remove(); 45 46 this.init(container, newCountryCode); 47 }, 48 init: function(container, newCountryCode) { 49 // If the container is not an Element terminate early 50 if (!container.tagName) { 51 console && console.error( 52 '[mapJustice] `container` is not an Element. `container`:', 53 container 54 ); 55 return; 56 } 57 58 width = container.clientWidth; 59 height = container.clientHeight + 150; // +150 Because of the long text loaded later 60 61 translateY = height / 2; 62 projection = d3.geoEquirectangular() 63 .translate([width * 0.8, translateY]) 64 .scale(width / scale); 65 66 canvas = d3.select(container).append('canvas') 67 .attr('width', width) 68 .attr('height', height); 69 70 context = canvas.node().getContext('2d'); 71 72 path = d3.geoPath(projection, context); 73 74 d3.queue() 75 .defer(d3.json, '/public/themes/amnesty/javascripts/world-110m.json') 76 .defer(d3.json, '/public/themes/amnesty/javascripts/world-110m-country-codes.json') 77 .await(ready.bind(this)); 78 79 function ready(error, world, names) { 80 if (error) { 81 console && console.error( 82 '[mapJustice] Error getting data:', 83 error 84 ); 85 return; 86 } 87 88 land = topojson.feature(world, world.objects.land); 89 countries = topojson.feature(world, world.objects.countries).features; 90 91 // Merge topojson earth with country codes 92 countries = countries.filter(function(d) { 93 return names.some(function(n) { 94 if (d.id == n.id) return d.code = n.code; 95 }); 96 }).sort(function(a, b) { 97 return a.code.localeCompare(b.code); 98 }); 99 100 this.ready = true; 101 var highlight = onReadyHighlight ? onReadyHighlight : newCountryCode; 102 this.highlight(highlight); 103 104 }; 105 }, 106 highlight: function(newCountryCode) { 107 if (!this.ready) { 108 onReadyHighlight = newCountryCode; 109 return; 110 } 111 112 newCountryCode = newCountryCode ? newCountryCode : ''; 113 var newCountry; 114 115 for (var k = countries.length - 1; k >= 0; k--) { 116 if (countries[k].code.toLowerCase() === newCountryCode.toLowerCase()) { 117 newCountry = countries[k]; 118 } 119 } 120 121 d3.transition() 122 .duration(1000) 123 .ease(d3.easePolyOut.exponent(5)) 124 .tween('trans', function() { 125 // get the top-left-most point of the country 126 var centroid = newCountry ? d3.geoCentroid(newCountry) : [0, 0]; 127 128 // limit the maximum Y offset so we don't show beyond the poles 129 if (centroid[1] > 43) centroid[1] = 43; 130 else if (centroid[1] < -43) centroid[1] = -43; 131 132 var pxCentroid = projection(centroid); 133 134 var rotationX = d3.interpolateNumber(projection.rotate()[0], -centroid[0]); 135 var translationY = d3.interpolateNumber(projection.translate()[1], 136 projection.translate()[1] - pxCentroid[1] + translateY); 137 138 // https://github.com/d3/d3-interpolate#interpolateNumber 139 // 1e-6 is the smallest value that is not stringified in scientific notation 140 var newOpacity = d3.interpolateNumber(1e-6, 1); 141 var oldOpacity = d3.interpolateNumber(1, 1e-6); 142 143 return function(t) { 144 projection.rotate([rotationX(t), 0, 0]); 145 projection.translate([projection.translate()[0], translationY(t)]); 146 147 context.clearRect(0, 0, width, height); 148 149 // land 150 context.beginPath(); 151 path(land); 152 context.fillStyle = landGray; 153 context.fill(); 154 155 // fade out old country 156 if (oldCountry) { 157 context.beginPath(); 158 path(oldCountry); 159 context.fillStyle = 'rgba(' + countryR + ',' + countryG + ',' + countryB + ',' + oldOpacity(Math.sqrt(t)) + ')'; 160 context.fill(); 161 } 162 163 // fade in new country 164 if (newCountry) { 165 context.beginPath(); 166 path(newCountry); 167 context.fillStyle = 'rgba(' + countryR + ',' + countryG + ',' + countryB + ',' + newOpacity(t) + ')'; 168 context.fill(); 169 } 170 }; 171 }) 172 .on('end', function() { 173 oldCountry = newCountry; 174 }); 175 176 } 177 }; 178 179 return mapJustice; 180}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.