Travel Map API

Generate interactive travel maps via URL parameters

Quick Example

https://travelmap.psiegel.org/?work=NY,CA,TX&personal=OH,HI&trips=NY:40,CA:9

URL Parameters

ParameterDescriptionExample
workStates visited for workNY,CA,TX,FL
personalStates visited personallyOH,HI,MI
provCanadian provinces (work)ON,BC,NL
provPersCanadian provinces (personal)QC,AB
tripsTrip counts (for shading)NY:40,CA:9,TX:17
titleCustom map titleMy Travel Map

Embed in MediaWiki

Add this to your wiki page where you want the map. The script parses your trip tables automatically:

<html>
<div id="travel-map-container"></div>
<script>
(function() {
  var stateCodes = new Set(['AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA','HI','ID','IL','IN','IA','KS','KY','LA','ME','MD','MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND','OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VT','VA','WA','WV','WI','WY']);
  var provCodes = new Set(['AB','BC','MB','NB','NL','NS','NT','NU','ON','PE','QC','SK','YT']);

  function extractLoc(text) {
    if (!text) return null;
    var prov = text.match(/,\s*([A-Z]{2})\s*,\s*Canada/i);
    if (prov && provCodes.has(prov[1].toUpperCase())) return { code: prov[1].toUpperCase(), isProv: true };
    var st = text.match(/,\s*([A-Z]{2})(?:\s*$|[^a-zA-Z])/);
    if (st && stateCodes.has(st[1])) return { code: st[1], isProv: false };
    return null;
  }

  var work = {}, personal = {}, provs = {};

  // Parse work tables (golive, immersion, adhoc)
  document.querySelectorAll('.golive-table tr, .immersion-table tr').forEach(function(r) {
    var c = r.querySelectorAll('td');
    if (c.length >= 4) {
      var res = extractLoc(c[c.length-1].textContent);
      if (res) { if (res.isProv) provs[res.code] = (provs[res.code]||0)+1; else work[res.code] = (work[res.code]||0)+1; }
    }
  });
  document.querySelectorAll('.adhoc-trip-table tr').forEach(function(r) {
    var c = r.querySelectorAll('td');
    if (c.length >= 4) {
      var res = extractLoc(c[3].textContent);
      if (res && !res.isProv) work[res.code] = (work[res.code]||0)+1;
    }
  });

  // Parse personal trips
  document.querySelectorAll('.personal-trips-table tr').forEach(function(r) {
    var c = r.querySelectorAll('td');
    if (c.length >= 1) {
      var res = extractLoc(c[0].textContent);
      if (res && !res.isProv) personal[res.code] = (personal[res.code]||0)+1;
    }
  });

  // Build URL
  var p = [], trips = {};
  if (Object.keys(work).length) p.push('work=' + Object.keys(work).join(','));
  if (Object.keys(personal).length) p.push('personal=' + Object.keys(personal).join(','));
  if (Object.keys(provs).length) p.push('prov=' + Object.keys(provs).join(','));
  for (var s in work) trips[s] = (trips[s]||0) + work[s];
  for (var s in personal) trips[s] = (trips[s]||0) + personal[s];
  for (var s in provs) trips[s] = (trips[s]||0) + provs[s];
  var tp = []; for (var k in trips) tp.push(k+':'+trips[k]);
  if (tp.length) p.push('trips=' + tp.join(','));
  p.push('title=' + encodeURIComponent("Preston's Travel Map"));

  var iframe = document.createElement('iframe');
  iframe.src = 'https://travelmap.psiegel.org/?' + p.join('&');
  iframe.style.cssText = 'width:100%;height:650px;border:none;border-radius:12px;';
  document.getElementById('travel-map-container').appendChild(iframe);
})();
</script>
</html>

Features

• Accurate US state and Canadian province borders using Leaflet + GeoJSON

• Color coding: Work (orange), Personal (pink), Both (purple)

• Intensity shading based on trip count

• Interactive hover tooltips and zoom