Skip to content
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
56 changes: 34 additions & 22 deletions sites/kit.svelte.dev/src/routes/edge.svg/+server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { geoPath } from 'd3-geo';
import { geoSatellite } from 'd3-geo-projection';
import * as topojson from 'topojson-client';
import topology from './land-110m.json';
import countries from './countries.json';

const land = topojson.feature(topology, topology.objects.land);

Expand All @@ -28,18 +29,27 @@ const projection = geoSatellite()
const path = geoPath(projection);

/**
* @param {number} lat
* @param {number} lon
* @param {string | null} lat
* @param {string | null} lon
* @param {string} city
* @param {string} country
*/
function render(lat, lon, city, country) {
projection.rotate([-lon - 10, -lat + 20, 0]);
const coords = lat && lon ? [+lon, +lat] : [-74, 40.7];

const [x, y] = projection([lon, lat]);
// spin globe a little west of the user's location so that it isn't
// dead centre, and tilt them slightly towards the vertical center
projection.rotate([-coords[0] - 30, -coords[1] * (30 / 90), 0]);

const sphere = path({ type: 'Sphere' });
const label = `${city}, ${country}`;
const dot = lon && lat ? projection([lon, lat]) : null;

const MAX_LABEL_LENGTH = 27;
const DEFAULT_LABEL = 'Your location';

let label = [city, country].filter(Boolean).join(', ') || DEFAULT_LABEL;
if (label.length > MAX_LABEL_LENGTH) label = city ?? DEFAULT_LABEL;
if (label.length > MAX_LABEL_LENGTH) label = country ?? DEFAULT_LABEL;
if (label.length > MAX_LABEL_LENGTH) label = DEFAULT_LABEL;

return `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}">
Expand Down Expand Up @@ -81,10 +91,13 @@ function render(lat, lon, city, country) {
}
</style>

<path d="${sphere}" class="ocean"/>
<path d="${path({ type: 'Sphere' })}" class="ocean"/>
<path d="${path(land)}" class="land"/>

<g transform="translate(${x},${y})">
${
dot
? `
<g transform="translate(${dot[0]},${dot[1]})">
<circle r="20" class="dot"/>
<rect x="50" y="-30" width="${font_size * 0.6 * label.length + 40}" height="60" class="highlight"/>
<polygon points="35,0 50,-10 50,10" class="highlight" />
Expand All @@ -96,27 +109,26 @@ function render(lat, lon, city, country) {
dominant-baseline="middle"
style="font-family: 'Courier', 'Courier New'; font-size: ${font_size}px; font-weight: bold"
>${label.toUpperCase()}</text>
</g>
</g>`
: ''
}
</svg>
`;
}

/** @type {import('./$types').RequestHandler} */
export function GET({ request, url }) {
const q = url.searchParams;
export function GET({ request }) {
const h = request.headers;

const latitude = q.get('lat') ?? h.get('x-vercel-ip-latitude') ?? '40.7';
const longitude = q.get('lon') ?? h.get('x-vercel-ip-longitude') ?? '-74';
const city = q.get('city') ?? h.get('x-vercel-ip-city') ?? 'New York City';
const country = q.get('country') ?? h.get('x-vercel-ip-country') ?? 'USA';

const svg = render(
+latitude,
+longitude,
decodeURIComponent(city),
decodeURIComponent(country)
).replace(/\d\.\d+/g, (match) => match.slice(0, 4));
const latitude = h.get('x-vercel-ip-latitude') ?? '';
const longitude = h.get('x-vercel-ip-longitude') ?? '';
const city = h.get('x-vercel-ip-city') ?? '';
const country = countries[h.get('x-vercel-ip-country')];

const svg = render(latitude, longitude, decodeURIComponent(city), country).replace(
/\d\.\d+/g,
(match) => match.slice(0, 4)
);

return new Response(svg, {
headers: {
Expand Down
251 changes: 251 additions & 0 deletions sites/kit.svelte.dev/src/routes/edge.svg/countries.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
{
"AF": "Afghanistan",
"AL": "Albania",
"DZ": "Algeria",
"AS": "American Samoa",
"AD": "Andorra",
"AO": "Angola",
"AI": "Anguilla",
"AQ": "Antarctica",
"AG": "Antigua and Barbuda",
"AR": "Argentina",
"AM": "Armenia",
"AW": "Aruba",
"AU": "Australia",
"AT": "Austria",
"AZ": "Azerbaijan",
"BS": "Bahamas (the)",
"BH": "Bahrain",
"BD": "Bangladesh",
"BB": "Barbados",
"BY": "Belarus",
"BE": "Belgium",
"BZ": "Belize",
"BJ": "Benin",
"BM": "Bermuda",
"BT": "Bhutan",
"BO": "Bolivia",
"BQ": "Bonaire, Sint Eustatius and Saba",
"BA": "Bosnia and Herzegovina",
"BW": "Botswana",
"BV": "Bouvet Island",
"BR": "Brazil",
"IO": "British Indian Ocean Territory",
"BN": "Brunei Darussalam",
"BG": "Bulgaria",
"BF": "Burkina Faso",
"BI": "Burundi",
"CV": "Cabo Verde",
"KH": "Cambodia",
"CM": "Cameroon",
"CA": "Canada",
"KY": "Cayman Islands",
"CF": "Central African Republic",
"TD": "Chad",
"CL": "Chile",
"CN": "China",
"CX": "Christmas Island",
"CC": "Cocos (Keeling) Islands",
"CO": "Colombia",
"KM": "Comoros",
"CD": "Congo (Kinshasa)",
"CG": "Congo (Brazzaville)",
"CK": "Cook Islands",
"CR": "Costa Rica",
"HR": "Croatia",
"CU": "Cuba",
"CW": "Curaçao",
"CY": "Cyprus",
"CZ": "Czechia",
"CI": "Côte d'Ivoire",
"DK": "Denmark",
"DJ": "Djibouti",
"DM": "Dominica",
"DO": "Dominican Republic",
"EC": "Ecuador",
"EG": "Egypt",
"SV": "El Salvador",
"GQ": "Equatorial Guinea",
"ER": "Eritrea",
"EE": "Estonia",
"SZ": "Eswatini",
"ET": "Ethiopia",
"FK": "Falkland Islands",
"FO": "Faroe Islands",
"FJ": "Fiji",
"FI": "Finland",
"FR": "France",
"GF": "French Guiana",
"PF": "French Polynesia",
"TF": "French Southern Territories",
"GA": "Gabon",
"GM": "Gambia",
"GE": "Georgia",
"DE": "Germany",
"GH": "Ghana",
"GI": "Gibraltar",
"GR": "Greece",
"GL": "Greenland",
"GD": "Grenada",
"GP": "Guadeloupe",
"GU": "Guam",
"GT": "Guatemala",
"GG": "Guernsey",
"GN": "Guinea",
"GW": "Guinea-Bissau",
"GY": "Guyana",
"HT": "Haiti",
"HM": "Heard Island and McDonald Islands",
"VA": "Holy See",
"HN": "Honduras",
"HK": "Hong Kong",
"HU": "Hungary",
"IS": "Iceland",
"IN": "India",
"ID": "Indonesia",
"IR": "Iran",
"IQ": "Iraq",
"IE": "Ireland",
"IM": "Isle of Man",
"IL": "Israel",
"IT": "Italy",
"JM": "Jamaica",
"JP": "Japan",
"JE": "Jersey",
"JO": "Jordan",
"KZ": "Kazakhstan",
"KE": "Kenya",
"KI": "Kiribati",
"KP": "DPRK",
"KR": "Republic of Korea",
"KW": "Kuwait",
"KG": "Kyrgyzstan",
"LA": "Laos",
"LV": "Latvia",
"LB": "Lebanon",
"LS": "Lesotho",
"LR": "Liberia",
"LY": "Libya",
"LI": "Liechtenstein",
"LT": "Lithuania",
"LU": "Luxembourg",
"MO": "Macao",
"MG": "Madagascar",
"MW": "Malawi",
"MY": "Malaysia",
"MV": "Maldives",
"ML": "Mali",
"MT": "Malta",
"MH": "Marshall Islands",
"MQ": "Martinique",
"MR": "Mauritania",
"MU": "Mauritius",
"YT": "Mayotte",
"MX": "Mexico",
"FM": "Micronesia",
"MD": "Moldova",
"MC": "Monaco",
"MN": "Mongolia",
"ME": "Montenegro",
"MS": "Montserrat",
"MA": "Morocco",
"MZ": "Mozambique",
"MM": "Myanmar",
"NA": "Namibia",
"NR": "Nauru",
"NP": "Nepal",
"NL": "Netherlands",
"NC": "New Caledonia",
"NZ": "New Zealand",
"NI": "Nicaragua",
"NE": "Niger",
"NG": "Nigeria",
"NU": "Niue",
"NF": "Norfolk Island",
"MP": "Northern Mariana Islands",
"NO": "Norway",
"OM": "Oman",
"PK": "Pakistan",
"PW": "Palau",
"PS": "Palestine",
"PA": "Panama",
"PG": "Papua New Guinea",
"PY": "Paraguay",
"PE": "Peru",
"PH": "Philippines",
"PN": "Pitcairn",
"PL": "Poland",
"PT": "Portugal",
"PR": "Puerto Rico",
"QA": "Qatar",
"MK": "North Macedonia",
"RO": "Romania",
"RU": "Russian Federation",
"RW": "Rwanda",
"RE": "Réunion",
"BL": "Saint Barthélemy",
"SH": "Saint Helena, Ascension and Tristan da Cunha",
"KN": "Saint Kitts and Nevis",
"LC": "Saint Lucia",
"MF": "Saint Martin (French part)",
"PM": "Saint Pierre and Miquelon",
"VC": "Saint Vincent and the Grenadines",
"WS": "Samoa",
"SM": "San Marino",
"ST": "Sao Tome and Principe",
"SA": "Saudi Arabia",
"SN": "Senegal",
"RS": "Serbia",
"SC": "Seychelles",
"SL": "Sierra Leone",
"SG": "Singapore",
"SX": "Sint Maarten (Dutch part)",
"SK": "Slovakia",
"SI": "Slovenia",
"SB": "Solomon Islands",
"SO": "Somalia",
"ZA": "South Africa",
"GS": "South Georgia and the South Sandwich Islands",
"SS": "South Sudan",
"ES": "Spain",
"LK": "Sri Lanka",
"SD": "Sudan (the)",
"SR": "Suriname",
"SJ": "Svalbard and Jan Mayen",
"SE": "Sweden",
"CH": "Switzerland",
"SY": "Syrian Arab Republic",
"TW": "Taiwan",
"TJ": "Tajikistan",
"TZ": "Tanzania",
"TH": "Thailand",
"TL": "Timor-Leste",
"TG": "Togo",
"TK": "Tokelau",
"TO": "Tonga",
"TT": "Trinidad and Tobago",
"TN": "Tunisia",
"TR": "Turkey",
"TM": "Turkmenistan",
"TC": "Turks and Caicos Islands (the)",
"TV": "Tuvalu",
"UG": "Uganda",
"UA": "Ukraine",
"AE": "UAE",
"GB": "UK",
"UM": "United States Minor Outlying Islands",
"US": "USA",
"UY": "Uruguay",
"UZ": "Uzbekistan",
"VU": "Vanuatu",
"VE": "Venezuela",
"VN": "Vietnam",
"VG": "British Virgin Islands",
"VI": "US Virgin Islands",
"WF": "Wallis and Futuna",
"EH": "Western Sahara",
"YE": "Yemen",
"ZM": "Zambia",
"ZW": "Zimbabwe",
"AX": "Åland Islands"
}