← Back to Projects Case Study · Team Project

Interactive World Travel Map

Vanilla JavaScript SVG Vector Map REST Countries API CSV Data Pipeline HTML & CSS
My role: Map design & development
The Travel Agent world map coloured for an Australian passport — showing visa-free countries in green, eVisa in orange and required in red.

About the Project

Travel Agent was my graduation project, built with a team during my final year at university. The goal was to make trip planning feel like exploring rather than researching — instead of juggling a dozen tabs, a traveller picks a country and gets everything in one place: general information, famous attractions, a live currency converter, seasonal weather, travel-risk and news, flight booking, and a traveller community.

The front door to all of that is the interactive world map. It answers the very first question every traveller asks — ”where can I actually go with my passport?” — and turns the answer into a single glance at a colour-coded globe. Every country on the map is a doorway into its full destination guide.

This page focuses on the feature I personally designed and built from scratch: the interactive map experience end to end — the visuals, the interaction model, and the data pipeline behind it.

My Role & Contribution

I owned the map feature from concept to working component. That meant designing how visa information should look on a map, building the rendering and interaction layer in plain JavaScript, and — the unglamorous but critical part — wrangling the raw passport dataset into something a browser can query instantly.

01Map experience design

Defined the six-state colour language, the legend, the hover tooltip, and the country side-panel so ~200 countries stay readable at once.

02Visa data pipeline

Turned a 35,000-row passport-index CSV into a pre-compiled lookup object with O(1) passport → destination access, no runtime parsing.

03Country reconciliation layer

Built the name ↔ ISO bridge that reconciles three different country-naming schemes (dataset, SVG map, REST Countries) so nothing renders grey by accident.

04Interaction & enrichment

Wired the map hooks: hover, recolour-on-select, click-to-open, and live country enrichment from the REST Countries API.

The country detail page in Travel Agent showing General Information for Argentina — population, area, region and key facts.

What the Interactive Map Does

The map starts neutral. The moment you choose a passport, every country repaints to show exactly what you’d need to enter it — and a running count tells you how much of the world is open to you. From there it’s built for browsing: hover for a quick verdict, click for the full picture.

  • Passport selector — 190+ nationalities, each with its own visa map.
  • Instant recolour — the whole world repaints in one pass on selection.
  • Six-state colour key — visa-free, on arrival, eVisa/ETA, visa required, no admission, your country.
  • Always-on legend — the colour meanings sit next to the map, never hidden in a menu.
  • Hover tooltip — country name plus the visa verdict for your passport.
  • Click a country — opens a detail panel with flag, capital, region, population, languages and currency.
  • Live counts — visa-free / on-arrival / eVisa / required totals update per passport.
  • Reset — clears the selection and returns the map to its neutral state.

Try It Yourself — Live Demo

This is the real component, running right here on the page. Pick a passport to colour the map, read the legend for what each colour means, then click any country to see its details.

Interactive Visa Map

Loads a vector world map plus the full passport-index dataset (~1.4 MB). Starts on tap.

Live component · vanilla JS · SVG vector map · REST Countries enrichment

How It Works — Technical Details

1 · Data pipeline

The source is passport-index-tidy.csv — every passport → destination → requirement row (~35k). I flatten it into a nested object, VISA_DATA["Germany"]["Japan"] = "90", shipped as a pre-built JS file so lookups are O(1) with zero parsing at runtime.

2 · Name ↔ ISO reconciliation

Three data sources spell countries differently (“DR Congo” vs “Democratic Republic of the Congo” vs CD). A CSV_TO_MAP table plus an ISO index resolves every name to the map’s country id, so no destination silently falls through to “no data”.

3 · Rendering & recolour

The map is an SVG vector engine. On passport select I reset all state_specific colours, paint each destination by category, mark the home country, then call one refresh() — the entire world repaints in a single frame.

4 · Visa classification

Raw values are messy — "visa on arrival", "e-visa", a number of days, "-1", blank. A classifyVisa() function normalises all of it into six semantic buckets that drive both colour and copy.

5 · Live country enrichment

Clicking a country fires a request to the REST Countries API for flag, capital, region, population, languages and currencies, merged with the visa verdict from the local dataset.

6 · Interaction hooks

The engine exposes over_state, out_state and click_state hooks. I use them for the follow-the-cursor tooltip, hover verdict badges, and opening the country panel.

Features I Implemented

  • Passport → world recolour in a single render pass.
  • Six-category visa colour system with an always-visible legend.
  • Normalisation layer for inconsistent visa strings and country names.
  • Pre-compiled dataset for instant, offline-capable lookups.
  • Cursor-tracking tooltip with per-passport verdicts.
  • Country detail panel with live API enrichment and graceful offline fallback.
  • Per-passport statistics (visa-free / on-arrival / eVisa / required).
  • Reset control and keyboard-dismissible panel.
  • Responsive framing so the map sits in the layout instead of taking the whole screen.

Challenges

01

Three sources, three spellings

The visa dataset, the SVG map, and the REST Countries API each name countries differently. Getting a fully-painted map meant building and testing a reconciliation table until zero destinations fell through to “no data”.

02

35,000 rows, instantly

Parsing a 1 MB CSV on every visit was a non-starter. Pre-compiling it into a nested lookup object moved all the cost to build time and made passport switching feel instant.

03

Readable with 200 countries lit up

Colouring the whole world at once can turn into noise. I settled on six high-contrast categories, a near-white “your country” marker, and a muted “no data” tone so the map stays scannable.

04

A map that doesn’t eat the page

An SVG world map wants to fill the viewport. I framed it in a fixed, rounded container with its own toolbar, legend and stats so it reads as one component inside the layout.

How the Map Improves the Travel Experience

The map replaces a dense visa table with a single glance. It changes the traveller’s first question from a spreadsheet lookup into an exploration — and every country is a launchpad into the rest of the platform.

1 glance

“Where can I go?” is answered visually instead of by reading rows of text.

190+

passports supported, each with its own full-world visa picture.

1 click

from a country on the map to its complete destination guide.

Lessons Learned

  • Most of the work in a “visual” feature is data cleaning — the rendering was the easy 20%.
  • Pre-computing at build time beats clever runtime parsing for anything the user waits on.
  • A colour system needs an offline “no data” and “home” state designed in from the start, not bolted on.
  • Embedding a full-bleed widget in a page is its own design problem — framing, legend and controls have to travel with it.

Project Demo Video

A walkthrough of the full Travel Agent platform recorded during our final-year presentation.