{"id":2283,"date":"2026-08-25T11:53:13","date_gmt":"2026-08-25T11:53:13","guid":{"rendered":"https:\/\/a2jobs.com\/Vanship_website_preview\/?page_id=2283"},"modified":"2026-09-06T14:04:35","modified_gmt":"2026-09-06T14:04:35","slug":"sea-port-locator","status":"publish","type":"page","link":"https:\/\/vanchile.com\/sea-port-locator\/","title":{"rendered":"\u00a0Sea Port Locator"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2283\" class=\"elementor elementor-2283\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4dc06f1 e-con-full e-flex e-con e-parent\" data-id=\"4dc06f1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d684ab5 elementor-widget elementor-widget-html\" data-id=\"d684ab5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div id=\"vanchile-port-directory\">\r\n\r\n<style>\r\n#vanchile-port-directory{\r\n  --primary:#F96C0A;\r\n  --primary-dark:#c95f1d;\r\n  --text:#1f2937;\r\n  --muted:#6b7280;\r\n  --border:#e5e7eb;\r\n  --bg:#f7f8fa;\r\n  --white:#fff;\r\n  --sea:#16834c;\r\n  --icd:#F96C0A;\r\n\r\n  width:100%;\r\n  font-family:Inter,Arial,Helvetica,sans-serif;\r\n  color:var(--text);\r\n}\r\n\r\n#vanchile-port-directory *,\r\n#vanchile-port-directory *::before,\r\n#vanchile-port-directory *::after{\r\n  box-sizing:border-box;\r\n}\r\n\r\n.vpd-container{\r\n  \r\n  width:100%;\r\n  margin:auto;\r\n  padding:0px;\r\n}\r\n\r\n.vpd-heading{\r\n  text-align:center;\r\n  margin-bottom:25px;\r\n}\r\n\r\n.vpd-heading h2{\r\n  margin:0 0 8px;\r\n  font-size:34px;\r\n  line-height:1.2;\r\n  font-weight:800;\r\n}\r\n\r\n.vpd-heading p{\r\n  max-width:800px;\r\n  margin:auto;\r\n  color:var(--muted);\r\n  font-size:15px;\r\n  line-height:1.7;\r\n}\r\n\r\n.vpd-card{\r\n  background:#fff;\r\n  border:1px solid var(--border);\r\n  \r\n  overflow:hidden;\r\n  box-shadow:0 15px 45px rgba(0,0,0,.07);\r\n}\r\n\r\n.vpd-filters{\r\n  padding:22px;\r\n  display:grid;\r\n  grid-template-columns:1fr 1fr 1fr 1.4fr;\r\n  gap:14px;\r\n  border-bottom:1px solid var(--border);\r\n}\r\n\r\n.vpd-field label{\r\n  display:block;\r\n  margin-bottom:7px;\r\n  font-size:12px;\r\n  font-weight:700;\r\n}\r\n\r\n.vpd-field select,\r\n.vpd-field input{\r\n  width:100%;\r\n  height:48px;\r\n  border:1px solid var(--border);\r\n  border-radius:9px;\r\n  padding:0 13px;\r\n  background:#fff;\r\n  color:var(--text);\r\n  font-size:14px;\r\n  outline:none;\r\n}\r\n\r\n.vpd-field select:focus,\r\n.vpd-field input:focus{\r\n  border-color:var(--primary);\r\n  box-shadow:0 0 0 3px rgba(249,108,10,.10);\r\n}\r\n\r\n.vpd-field select:disabled,\r\n.vpd-field input:disabled{\r\n  background:#f3f4f6;\r\n  color:#9ca3af;\r\n}\r\n\r\n.vpd-search{\r\n  position:relative;\r\n}\r\n\r\n.vpd-search-icon{\r\n  position:absolute;\r\n  left:13px;\r\n  top:14px;\r\n  color:var(--muted);\r\n  pointer-events:none;\r\n}\r\n\r\n.vpd-search input{\r\n  padding-left:38px;\r\n}\r\n\r\n.vpd-content{\r\n  display:grid;\r\n  grid-template-columns:43% 57%;\r\n  min-height:620px;\r\n}\r\n\r\n.vpd-results{\r\n  order:1;\r\n  min-width:0;\r\n  border-right:1px solid var(--border);\r\n}\r\n\r\n.vpd-results-header{\r\n  padding:18px;\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:space-between;\r\n  border-bottom:1px solid var(--border);\r\n}\r\n\r\n.vpd-results-title{\r\n  font-size:17px;\r\n  font-weight:800;\r\n}\r\n\r\n.vpd-count{\r\n  background:#fff1e8;\r\n  color:var(--primary);\r\n  padding:5px 10px;\r\n  border-radius:20px;\r\n  font-size:11px;\r\n  font-weight:800;\r\n}\r\n\r\n.vpd-list{\r\n  max-height:560px;\r\n  overflow-y:auto;\r\n}\r\n\r\n.vpd-result{\r\n  padding:17px;\r\n  border-bottom:1px solid #f0f0f0;\r\n  cursor:pointer;\r\n  transition:.2s;\r\n}\r\n\r\n.vpd-result:hover{\r\n  background:#fff9f5;\r\n}\r\n\r\n.vpd-result.active{\r\n  background:#fff4ed;\r\n  border-left:4px solid var(--primary);\r\n  padding-left:13px;\r\n}\r\n\r\n.vpd-result-top{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  align-items:flex-start;\r\n  gap:10px;\r\n}\r\n\r\n.vpd-result h3{\r\n  margin:0 0 6px;\r\n  font-size:15px;\r\n  line-height:1.4;\r\n}\r\n\r\n.vpd-location{\r\n  color:var(--muted);\r\n  font-size:11px;\r\n  margin-bottom:6px;\r\n}\r\n\r\n.vpd-code{\r\n  color:#9ca3af;\r\n  font-size:10px;\r\n}\r\n\r\n.vpd-type{\r\n  padding:4px 7px;\r\n  border-radius:5px;\r\n  font-size:10px;\r\n  font-weight:800;\r\n  white-space:nowrap;\r\n}\r\n\r\n.vpd-type.sea{\r\n  color:#087443;\r\n  background:#eaf8f0;\r\n}\r\n\r\n.vpd-type.icd{\r\n  color:#875500;\r\n  background:#fff5d9;\r\n}\r\n\r\n.vpd-footer{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  align-items:center;\r\n  gap:10px;\r\n  margin-top:12px;\r\n}\r\n\r\n.vpd-map-link{\r\n  color:var(--primary);\r\n  font-size:11px;\r\n  font-weight:700;\r\n}\r\n\r\n.vpd-view{\r\n  display:inline-flex;\r\n  align-items:center;\r\n  justify-content:center;\r\n  min-height:34px;\r\n  padding:0 12px;\r\n  border-radius:7px;\r\n  background:var(--primary);\r\n  color:#fff!important;\r\n  text-decoration:none!important;\r\n  font-size:11px;\r\n  font-weight:800;\r\n}\r\n\r\n.vpd-view:hover{\r\n  background:var(--primary-dark);\r\n}\r\n\r\n.vpd-map-wrap{\r\n  position:relative;\r\n  order:2;\r\n  min-width:0;\r\n}\r\n\r\n#vpd-map{\r\n  width:100%;\r\n  height:620px;\r\n}\r\n\r\n.vpd-map-tools{\r\n  position:absolute;\r\n  top:15px;\r\n  right:15px;\r\n  z-index:500;\r\n  display:flex;\r\n  flex-direction:column;\r\n  gap:7px;\r\n}\r\n\r\n.vpd-map-btn{\r\n  width:42px;\r\n  height:42px;\r\n  border:1px solid var(--border);\r\n  background:#fff;\r\n  border-radius:8px;\r\n  cursor:pointer;\r\n  box-shadow:0 3px 12px rgba(0,0,0,.12);\r\n}\r\n\r\n.vpd-map-btn:hover{\r\n  color:var(--primary);\r\n  border-color:var(--primary);\r\n}\r\n\r\n.vpd-legend{\r\n  position:absolute;\r\n  bottom:20px;\r\n  left:15px;\r\n  z-index:500;\r\n  background:#fff;\r\n  padding:10px 12px;\r\n  border:1px solid var(--border);\r\n  border-radius:9px;\r\n  box-shadow:0 3px 12px rgba(0,0,0,.12);\r\n  font-size:11px;\r\n}\r\n\r\n.vpd-legend-item{\r\n  display:flex;\r\n  align-items:center;\r\n  gap:7px;\r\n  margin:4px 0;\r\n}\r\n\r\n.vpd-dot{\r\n  width:10px;\r\n  height:10px;\r\n  border-radius:50%;\r\n}\r\n\r\n.vpd-dot.sea{\r\n  background:var(--sea);\r\n}\r\n\r\n.vpd-dot.icd{\r\n  background:var(--icd);\r\n}\r\n\r\n.vpd-empty{\r\n  padding:55px 20px;\r\n  text-align:center;\r\n  color:var(--muted);\r\n}\r\n\r\n.vpd-empty-icon{\r\n  font-size:36px;\r\n  margin-bottom:10px;\r\n}\r\n\r\n.vpd-quote{\r\n  padding:22px;\r\n  background:linear-gradient(135deg,#fff7f1,#fff);\r\n  border-top:1px solid var(--border);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:space-between;\r\n  gap:20px;\r\n}\r\n\r\n.vpd-quote h3{\r\n  margin:0 0 5px;\r\n  font-size:18px;\r\n}\r\n\r\n.vpd-quote p{\r\n  margin:0;\r\n  color:var(--muted);\r\n  font-size:12px;\r\n}\r\n\r\n.vpd-quote-button{\r\n  display:inline-flex;\r\n  align-items:center;\r\n  justify-content:center;\r\n  min-height:46px;\r\n  padding:0 25px;\r\n  background:var(--primary);\r\n  color:#fff!important;\r\n  text-decoration:none!important;\r\n  border-radius:9px;\r\n  font-size:13px;\r\n  font-weight:800;\r\n  white-space:nowrap;\r\n}\r\n\r\n.vpd-marker{\r\n  width:34px;\r\n  height:34px;\r\n  border-radius:50% 50% 50% 0;\r\n  transform:rotate(-45deg);\r\n  display:flex;\r\n  align-items:center;\r\n  justify-content:center;\r\n  border:3px solid #fff;\r\n  box-shadow:0 4px 12px rgba(0,0,0,.25);\r\n}\r\n\r\n.vpd-marker-inner{\r\n  transform:rotate(45deg);\r\n  color:#fff;\r\n  font-size:13px;\r\n}\r\n\r\n.vpd-marker.sea{\r\n  background:var(--sea);\r\n}\r\n\r\n.vpd-marker.icd{\r\n  background:var(--primary);\r\n}\r\n\r\n@media(max-width:1000px){\r\n\r\n  .vpd-filters{\r\n    grid-template-columns:1fr 1fr;\r\n  }\r\n\r\n}\r\n\r\n@media(max-width:750px){\r\n\r\n  .vpd-container{\r\n    padding:10px;\r\n  }\r\n\r\n  .vpd-heading h2{\r\n    font-size:26px;\r\n  }\r\n\r\n  .vpd-filters{\r\n    grid-template-columns:1fr;\r\n    padding:15px;\r\n  }\r\n\r\n  .vpd-content{\r\n    display:flex;\r\n    flex-direction:column;\r\n  }\r\n\r\n  .vpd-map-wrap{\r\n    order:1;\r\n  }\r\n\r\n  .vpd-results{\r\n    order:2;\r\n    border-right:0;\r\n    border-top:1px solid var(--border);\r\n  }\r\n\r\n  #vpd-map{\r\n    height:430px;\r\n  }\r\n\r\n  .vpd-list{\r\n    max-height:450px;\r\n  }\r\n\r\n  .vpd-quote{\r\n    flex-direction:column;\r\n    text-align:center;\r\n    align-items:stretch;\r\n  }\r\n\r\n  .vpd-quote-button{\r\n    width:100%;\r\n  }\r\n\r\n}\r\n\r\n@media(max-width:480px){\r\n\r\n  .vpd-heading h2{\r\n    font-size:23px;\r\n  }\r\n\r\n  #vpd-map{\r\n    height:390px;\r\n  }\r\n\r\n  .vpd-result-top{\r\n    flex-direction:column;\r\n  }\r\n\r\n  .vpd-footer{\r\n    align-items:stretch;\r\n  }\r\n\r\n  .vpd-view{\r\n    width:100%;\r\n  }\r\n\r\n}\r\n<\/style>\r\n\r\n\r\n<div class=\"vpd-container\">\r\n\r\n  \r\n\r\n\r\n  <div class=\"vpd-card\">\r\n\r\n\r\n    <div class=\"vpd-filters\">\r\n\r\n      <div class=\"vpd-field\">\r\n\r\n        <label>Country<\/label>\r\n\r\n        <select id=\"vpd-country\">\r\n\r\n          <option value=\"\">\r\n            Select Country\r\n          <\/option>\r\n\r\n        <\/select>\r\n\r\n      <\/div>\r\n\r\n\r\n      <div class=\"vpd-field\">\r\n\r\n        <label>State \/ Region<\/label>\r\n\r\n        <select id=\"vpd-state\" disabled>\r\n\r\n          <option value=\"all\">\r\n            All States \/ Regions\r\n          <\/option>\r\n\r\n        <\/select>\r\n\r\n      <\/div>\r\n\r\n\r\n      <div class=\"vpd-field\">\r\n\r\n        <label>Facility Type<\/label>\r\n\r\n        <select id=\"vpd-type\" disabled>\r\n\r\n          <option value=\"all\">\r\n            All Facilities\r\n          <\/option>\r\n\r\n          <option value=\"sea\">\r\n            Sea Port\r\n          <\/option>\r\n\r\n          <option value=\"icd\">\r\n            ICD\r\n          <\/option>\r\n\r\n        <\/select>\r\n\r\n      <\/div>\r\n\r\n\r\n      <div class=\"vpd-field\">\r\n\r\n        <label>Search Location<\/label>\r\n\r\n        <div class=\"vpd-search\">\r\n\r\n          <span class=\"vpd-search-icon\">\r\n            \ud83d\udd0e\r\n          <\/span>\r\n\r\n          <input\r\n            id=\"vpd-search\"\r\n            type=\"search\"\r\n            placeholder=\"Search port, ICD, city or code...\"\r\n            disabled\r\n          >\r\n\r\n        <\/div>\r\n\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n\r\n    <div class=\"vpd-content\">\r\n\r\n\r\n      <div class=\"vpd-results\">\r\n\r\n        <div class=\"vpd-results-header\">\r\n\r\n          <div class=\"vpd-results-title\">\r\n            Ports & ICDs\r\n          <\/div>\r\n\r\n          <div id=\"vpd-count\" class=\"vpd-count\">\r\n            0\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n\r\n        <div id=\"vpd-list\" class=\"vpd-list\">\r\n\r\n          <div class=\"vpd-empty\">\r\n\r\n            <div class=\"vpd-empty-icon\">\r\n              \ud83c\udf0d\r\n            <\/div>\r\n\r\n            <div>\r\n              Select a country to explore\r\n              sea ports and ICDs.\r\n            <\/div>\r\n\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n      <\/div>\r\n\r\n\r\n      <div class=\"vpd-map-wrap\">\r\n\r\n        <div id=\"vpd-map\"><\/div>\r\n\r\n\r\n        <div class=\"vpd-map-tools\">\r\n\r\n          <button\r\n            type=\"button\"\r\n            id=\"vpd-world\"\r\n            class=\"vpd-map-btn\"\r\n            title=\"World\">\r\n\r\n            \ud83c\udf0d\r\n\r\n          <\/button>\r\n\r\n\r\n          <button\r\n            type=\"button\"\r\n            id=\"vpd-fullscreen\"\r\n            class=\"vpd-map-btn\"\r\n            title=\"Fullscreen\">\r\n\r\n            \u26f6\r\n\r\n          <\/button>\r\n\r\n        <\/div>\r\n\r\n\r\n        <div class=\"vpd-legend\">\r\n\r\n          <div class=\"vpd-legend-item\">\r\n\r\n            <span class=\"vpd-dot sea\"><\/span>\r\n\r\n            Sea Port\r\n\r\n          <\/div>\r\n\r\n\r\n          <div class=\"vpd-legend-item\">\r\n\r\n            <span class=\"vpd-dot icd\"><\/span>\r\n\r\n            ICD\r\n\r\n          <\/div>\r\n\r\n        <\/div>\r\n\r\n      <\/div>\r\n\r\n    <\/div>\r\n\r\n\r\n    <div class=\"vpd-quote\">\r\n\r\n      <div>\r\n\r\n        <h3>\r\n          Need a freight quote?\r\n        <\/h3>\r\n\r\n        <p>\r\n          Get competitive shipping rates and logistics support.\r\n        <\/p>\r\n\r\n      <\/div>\r\n\r\n\r\n      <a\r\n        href=\"\/request-a-quote\/\"\r\n        class=\"vpd-quote-button\">\r\n\r\n        Request a Quote \u2192\r\n\r\n      <\/a>\r\n\r\n    <\/div>\r\n\r\n  <\/div>\r\n\r\n<\/div>\r\n\r\n\r\n<link\r\n  rel=\"stylesheet\"\r\n  href=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\"\r\n>\r\n\r\n<script src=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\"><\/script>\r\n\r\n\r\n<script>\r\n\r\n(function(){\r\n\r\n\"use strict\";\r\n\r\n\r\n\/* ==========================================================\r\n   DATABASE\r\n   ========================================================== *\/\r\n\r\nconst JSON_URL =\r\n  \"https:\/\/a2jobs.com\/Vanship_website_preview\/wp-content\/uploads\/2026\/09\/World_Ports_Batch2.json\";\r\n\r\nlet PORTS = [];\r\n\r\n\/*\r\n  JSON source fields:\r\n  Country\r\n  Region\r\n  Port \/ location\r\n  Local name\r\n  UN\/LOCODE\r\n  Type\r\n  Maritime\r\n  Rail\r\n  Road\r\n  Multimodal\r\n  Subdivision\r\n  Latitude\r\n  Longitude\r\n  Vanchile tier\r\n  Geo focus\r\n\r\n  Type mapping:\r\n  Seaport (UN\/LOCODE)     -> sea\r\n  Dry port \/ ICD \/ CFS    -> icd\r\n  Inland multimodal terminal -> icd\r\n  Multimodal facility    -> icd\r\n*\/\r\n\r\nfunction normalizePort(row){\r\n\r\n  const rawType = String(row[\"Type\"] || \"\").toLowerCase();\r\n\r\n  let facilityType = \"\";\r\n\r\n  if(rawType.includes(\"seaport\")){\r\n    facilityType = \"sea\";\r\n  }\r\n  else if(\r\n    rawType.includes(\"dry port\") ||\r\n    rawType.includes(\"icd\") ||\r\n    rawType.includes(\"cfs\") ||\r\n    rawType.includes(\"inland multimodal\") ||\r\n    rawType.includes(\"multimodal facility\")\r\n  ){\r\n    facilityType = \"icd\";\r\n  }\r\n  else{\r\n    return null;\r\n  }\r\n\r\n  const lat = Number(row[\"Latitude\"]);\r\n  const lng = Number(row[\"Longitude\"]);\r\n\r\n  if(!Number.isFinite(lat) || !Number.isFinite(lng)){\r\n    return null;\r\n  }\r\n\r\n  const country = String(row[\"Country\"] || \"\").trim();\r\n  const location = String(\r\n    row[\"Port \/ location\"] ||\r\n    row[\"Local name\"] ||\r\n    \"\"\r\n  ).trim();\r\n\r\n  const localName = String(row[\"Local name\"] || \"\").trim();\r\n\r\n  return {\r\n    name: location || localName || \"Unnamed location\",\r\n    localName: localName,\r\n    country: country,\r\n    code: String(row[\"UN\/LOCODE\"] || \"\").trim(),\r\n    state: String(\r\n      row[\"Subdivision\"] ||\r\n      row[\"Region\"] ||\r\n      \"\"\r\n    ).trim(),\r\n    region: String(row[\"Region\"] || \"\").trim(),\r\n    city: location || \"Location\",\r\n    type: facilityType,\r\n    rawType: String(row[\"Type\"] || \"\").trim(),\r\n    functions: String(row[\"Functions\"] || \"\").trim(),\r\n    maritime: String(row[\"Maritime\"] || \"\").trim(),\r\n    rail: String(row[\"Rail\"] || \"\").trim(),\r\n    road: String(row[\"Road\"] || \"\").trim(),\r\n    multimodal: String(row[\"Multimodal\"] || \"\").trim(),\r\n    tier: String(row[\"Vanchile tier\"] || \"\").trim(),\r\n    geoFocus: String(row[\"Geo focus\"] || \"\").trim(),\r\n    lat: lat,\r\n    lng: lng\r\n  };\r\n}\r\n\r\nasync function loadDatabase(){\r\n\r\n  try{\r\n\r\n    const response = await fetch(\r\n      JSON_URL + \"?v=\" + Date.now(),\r\n      {\r\n        method:\"GET\",\r\n        cache:\"no-store\",\r\n        credentials:\"omit\",\r\n        headers:{\"Accept\":\"application\/json\"}\r\n      }\r\n    );\r\n\r\n    if(!response.ok){\r\n      throw new Error(\r\n        \"JSON request failed: HTTP \" + response.status\r\n      );\r\n    }\r\n\r\n    const rows = await response.json();\r\n\r\n    if(!Array.isArray(rows)){\r\n      throw new Error(\"JSON format is not an array.\");\r\n    }\r\n\r\n    PORTS = rows\r\n      .map(normalizePort)\r\n      .filter(Boolean);\r\n\r\n    populateCountries();\r\n\r\n    country.disabled = false;\r\n\r\n    state.disabled = true;\r\n    type.disabled = true;\r\n    search.disabled = true;\r\n\r\n    count.textContent = \"0\";\r\n\r\n    list.innerHTML =\r\n      '<div class=\"vpd-empty\">' +\r\n        '<div class=\"vpd-empty-icon\">\ud83c\udf0d<\/div>' +\r\n        '<div>' +\r\n          'Loaded ' + PORTS.length.toLocaleString() + ' locations. Select a country to explore sea ports and ICDs.' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n\r\n  }\r\n  catch(error){\r\n\r\n    console.error(\r\n      \"Vanchile port database error:\",\r\n      error\r\n    );\r\n\r\n    country.disabled = true;\r\n    state.disabled = true;\r\n    type.disabled = true;\r\n    search.disabled = true;\r\n\r\n    count.textContent = \"0\";\r\n\r\n    list.innerHTML =\r\n      '<div class=\"vpd-empty\">' +\r\n        '<div class=\"vpd-empty-icon\">\u26a0\ufe0f<\/div>' +\r\n        '<div>' +\r\n          '<strong>Port database could not be loaded.<\/strong><br>' +\r\n          '<small>Please check the JSON URL, CORS settings, or try again.<\/small>' +\r\n        '<\/div>' +\r\n      '<\/div>';\r\n  }\r\n\r\n}\r\n\r\n\/* ==========================================================\r\n   DOM\r\n   ========================================================== *\/\r\n\r\nconst country =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-country\"\r\n);\r\n\r\nconst state =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-state\"\r\n);\r\n\r\nconst type =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-type\"\r\n);\r\n\r\nconst search =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-search\"\r\n);\r\n\r\nconst list =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-list\"\r\n);\r\n\r\nconst count =\r\ndocument.querySelector(\r\n  \"#vanchile-port-directory #vpd-count\"\r\n);\r\n\r\n\r\n\/* ==========================================================\r\n   MAP\r\n========================================================== *\/\r\n\r\nconst map =\r\nL.map(\r\n  document.querySelector(\r\n    \"#vanchile-port-directory #vpd-map\"\r\n  ),\r\n  {\r\n    scrollWheelZoom:true\r\n  }\r\n).setView(\r\n  [20,0],\r\n  2\r\n);\r\n\r\n\r\nL.tileLayer(\r\n  \"https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png\",\r\n  {\r\n    maxZoom:19,\r\n    attribution:\r\n      \"\u00a9 OpenStreetMap contributors\"\r\n  }\r\n).addTo(map);\r\n\r\n\r\nlet markers=[];\r\n\r\n\r\n\/* ==========================================================\r\n   COUNTRIES\r\n   ========================================================== *\/\r\n\r\nfunction populateCountries(){\r\n\r\n  country.innerHTML =\r\n    '<option value=\"\">Select Country<\/option>';\r\n\r\n  const countries = [\r\n    ...new Set(\r\n      PORTS\r\n        .map(item => item.country)\r\n        .filter(Boolean)\r\n    )\r\n  ].sort(\r\n    (a,b) => a.localeCompare(b)\r\n  );\r\n\r\n  countries.forEach(\r\n    function(item){\r\n\r\n      const option =\r\n        document.createElement(\"option\");\r\n\r\n      option.value = item;\r\n      option.textContent = item;\r\n\r\n      country.appendChild(option);\r\n\r\n    }\r\n  );\r\n\r\n  count.textContent = PORTS.length;\r\n}\r\n\r\n\/* ==========================================================\r\n   STATES\r\n========================================================== *\/\r\n\r\nfunction loadStates(){\r\n\r\n  const selected =\r\n    country.value;\r\n\r\n  const states =\r\n  [\r\n    ...new Set(\r\n\r\n      PORTS\r\n        .filter(\r\n          item =>\r\n            item.country === selected\r\n        )\r\n        .map(\r\n          item =>\r\n            item.state\r\n        )\r\n        .filter(Boolean)\r\n\r\n    )\r\n  ].sort();\r\n\r\n\r\n  state.innerHTML =\r\n    '<option value=\"all\">' +\r\n    'All States \/ Regions' +\r\n    '<\/option>';\r\n\r\n\r\n  states.forEach(\r\n    function(item){\r\n\r\n      const option =\r\n        document.createElement(\r\n          \"option\"\r\n        );\r\n\r\n      option.value=item;\r\n      option.textContent=item;\r\n\r\n      state.appendChild(\r\n        option\r\n      );\r\n\r\n    }\r\n  );\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   FILTER\r\n========================================================== *\/\r\n\r\nfunction getFiltered(){\r\n\r\n  const selectedCountry =\r\n    country.value;\r\n\r\n  const selectedState =\r\n    state.value;\r\n\r\n  const selectedType =\r\n    type.value;\r\n\r\n  const query =\r\n    search.value\r\n      .toLowerCase()\r\n      .trim();\r\n\r\n\r\n  return PORTS.filter(\r\n    function(item){\r\n\r\n      if(\r\n        selectedCountry &&\r\n        item.country !== selectedCountry\r\n      ){\r\n        return false;\r\n      }\r\n\r\n\r\n      if(\r\n        selectedState !== \"all\" &&\r\n        item.state !== selectedState\r\n      ){\r\n        return false;\r\n      }\r\n\r\n\r\n      if(\r\n        selectedType !== \"all\" &&\r\n        item.type !== selectedType\r\n      ){\r\n        return false;\r\n      }\r\n\r\n\r\n      if(query){\r\n\r\n        const text =\r\n          (\r\n            item.name +\r\n            \" \" +\r\n            item.city +\r\n            \" \" +\r\n            item.state +\r\n            \" \" +\r\n            item.country +\r\n            \" \" +\r\n            item.code\r\n          ).toLowerCase();\r\n\r\n\r\n        if(\r\n          !text.includes(query)\r\n        ){\r\n          return false;\r\n        }\r\n\r\n      }\r\n\r\n\r\n      return true;\r\n\r\n    }\r\n  );\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   MARKER\r\n========================================================== *\/\r\n\r\nfunction createMarker(item){\r\n\r\n  const icon =\r\n    item.type === \"sea\"\r\n      ? \"\u2693\"\r\n      : \"\u25a3\";\r\n\r\n\r\n  return L.divIcon({\r\n\r\n    className:\"\",\r\n\r\n    html:\r\n\r\n      '<div class=\"vpd-marker ' +\r\n        item.type +\r\n      '\">' +\r\n\r\n        '<div class=\"vpd-marker-inner\">' +\r\n\r\n          icon +\r\n\r\n        '<\/div>' +\r\n\r\n      '<\/div>',\r\n\r\n    iconSize:[\r\n      34,\r\n      34\r\n    ],\r\n\r\n    iconAnchor:[\r\n      17,\r\n      34\r\n    ]\r\n\r\n  });\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   CLEAR MAP\r\n========================================================== *\/\r\n\r\nfunction clearMarkers(){\r\n\r\n  markers.forEach(\r\n    function(marker){\r\n\r\n      map.removeLayer(\r\n        marker\r\n      );\r\n\r\n    }\r\n  );\r\n\r\n  markers=[];\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   RENDER\r\n========================================================== *\/\r\n\r\nfunction render(){\r\n\r\n  const filtered =\r\n    getFiltered();\r\n\r\n\r\n  clearMarkers();\r\n\r\n\r\n  count.textContent =\r\n    filtered.length;\r\n\r\n\r\n  if(\r\n    !filtered.length\r\n  ){\r\n\r\n    list.innerHTML =\r\n\r\n      '<div class=\"vpd-empty\">' +\r\n\r\n        '<div class=\"vpd-empty-icon\">' +\r\n          '\ud83d\udd0e' +\r\n        '<\/div>' +\r\n\r\n        '<div>' +\r\n          'No sea ports or ICDs found.' +\r\n        '<\/div>' +\r\n\r\n      '<\/div>';\r\n\r\n    return;\r\n\r\n  }\r\n\r\n\r\n  list.innerHTML=\"\";\r\n\r\n\r\n  const bounds=[];\r\n\r\n\r\n  filtered.forEach(\r\n    function(item){\r\n\r\n      const card =\r\n        document.createElement(\r\n          \"div\"\r\n        );\r\n\r\n\r\n      card.className =\r\n        \"vpd-result\";\r\n\r\n\r\n      const typeName =\r\n        item.type === \"sea\"\r\n          ? \"Sea Port\"\r\n          : \"ICD\";\r\n\r\n\r\n      const icon =\r\n        item.type === \"sea\"\r\n          ? \"\u2693\"\r\n          : \"\ud83d\udce6\";\r\n\r\n\r\n      const mapUrl =\r\n        \"https:\/\/www.openstreetmap.org\/?mlat=\" +\r\n        encodeURIComponent(item.lat) +\r\n        \"&mlon=\" +\r\n        encodeURIComponent(item.lng) +\r\n        \"#map=12\/\" +\r\n        encodeURIComponent(item.lat) +\r\n        \"\/\" +\r\n        encodeURIComponent(item.lng);\r\n\r\n      card.innerHTML =\r\n\r\n        '<div class=\"vpd-result-top\">' +\r\n\r\n          '<div>' +\r\n\r\n            '<h3>' +\r\n\r\n              icon +\r\n              \" \" +\r\n\r\n              escapeHTML(\r\n                item.name\r\n              ) +\r\n\r\n            '<\/h3>' +\r\n\r\n            '<div class=\"vpd-location\">' +\r\n\r\n              escapeHTML(\r\n                item.state || item.region || \"\"\r\n              ) +\r\n\r\n              \" \u2022 \" +\r\n\r\n              escapeHTML(\r\n                item.country\r\n              ) +\r\n\r\n            '<\/div>' +\r\n\r\n            '<div class=\"vpd-code\">' +\r\n\r\n              \"UN\/LOCODE: \" +\r\n\r\n              escapeHTML(\r\n                item.code || \"\u2014\"\r\n              ) +\r\n\r\n            '<\/div>' +\r\n\r\n          '<\/div>' +\r\n\r\n          '<span class=\"vpd-type ' +\r\n            item.type +\r\n          '\">' +\r\n\r\n            typeName +\r\n\r\n          '<\/span>' +\r\n\r\n        '<\/div>' +\r\n\r\n        '<div class=\"vpd-footer\">' +\r\n\r\n          '<span class=\"vpd-map-link\">' +\r\n            'View on map \u2192' +\r\n          '<\/span>' +\r\n\r\n          '<a ' +\r\n            'href=\"' + mapUrl + '\" ' +\r\n            'target=\"_blank\" ' +\r\n            'rel=\"noopener\" ' +\r\n            'class=\"vpd-view\">' +\r\n            'Open Map \u2192' +\r\n          '<\/a>' +\r\n\r\n        '<\/div>';\r\n\r\n\r\n      const marker =\r\n        L.marker(\r\n          [\r\n            item.lat,\r\n            item.lng\r\n          ],\r\n          {\r\n            icon:\r\n              createMarker(item)\r\n          }\r\n        ).addTo(map);\r\n\r\n\r\n      marker.bindPopup(\r\n\r\n        '<strong>' +\r\n\r\n          escapeHTML(\r\n            item.name\r\n          ) +\r\n\r\n        '<\/strong><br>' +\r\n\r\n        escapeHTML(\r\n          item.state || item.region || \"\"\r\n        ) +\r\n\r\n        ' \u2022 ' +\r\n\r\n        escapeHTML(\r\n          item.country\r\n        ) +\r\n\r\n        '<br>' +\r\n\r\n        'UN\/LOCODE: ' +\r\n\r\n        escapeHTML(\r\n          item.code || \"\u2014\"\r\n        ) +\r\n\r\n        '<br>' +\r\n\r\n        typeName +\r\n\r\n        '<br>' +\r\n\r\n        'Coordinates: ' +\r\n\r\n        Number(item.lat).toFixed(5) +\r\n\r\n        ', ' +\r\n\r\n        Number(item.lng).toFixed(5)\r\n\r\n      );\r\n\r\n\r\n      markers.push(\r\n        marker\r\n      );\r\n\r\n\r\n      bounds.push(\r\n        [\r\n          item.lat,\r\n          item.lng\r\n        ]\r\n      );\r\n\r\n\r\n      card.addEventListener(\r\n        \"click\",\r\n        function(event){\r\n\r\n          if(\r\n            event.target.closest(\"a\")\r\n          ){\r\n            return;\r\n          }\r\n\r\n\r\n          document\r\n            .querySelectorAll(\r\n              \"#vanchile-port-directory .vpd-result\"\r\n            )\r\n            .forEach(\r\n              el =>\r\n                el.classList.remove(\r\n                  \"active\"\r\n                )\r\n            );\r\n\r\n\r\n          card.classList.add(\r\n            \"active\"\r\n          );\r\n\r\n\r\n          map.setView(\r\n            [\r\n              item.lat,\r\n              item.lng\r\n            ],\r\n            10,\r\n            {\r\n              animate:true\r\n            }\r\n          );\r\n\r\n\r\n          marker.openPopup();\r\n\r\n        }\r\n      );\r\n\r\n\r\n      list.appendChild(\r\n        card\r\n      );\r\n\r\n    }\r\n  );\r\n\r\n\r\n  if(\r\n    bounds.length === 1\r\n  ){\r\n\r\n    map.setView(\r\n      bounds[0],\r\n      9\r\n    );\r\n\r\n  }\r\n  else if(\r\n    bounds.length > 1\r\n  ){\r\n\r\n    map.fitBounds(\r\n      bounds,\r\n      {\r\n        padding:[\r\n          35,\r\n          35\r\n        ],\r\n        maxZoom:8\r\n      }\r\n    );\r\n\r\n  }\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   ESCAPE\r\n========================================================== *\/\r\n\r\nfunction escapeHTML(value){\r\n\r\n  return String(\r\n    value || \"\"\r\n  )\r\n  .replace(\r\n    \/&\/g,\r\n    \"&amp;\"\r\n  )\r\n  .replace(\r\n    \/<\/g,\r\n    \"&lt;\"\r\n  )\r\n  .replace(\r\n    \/>\/g,\r\n    \"&gt;\"\r\n  )\r\n  .replace(\r\n    \/\"\/g,\r\n    \"&quot;\"\r\n  )\r\n  .replace(\r\n    \/'\/g,\r\n    \"&#039;\"\r\n  );\r\n\r\n}\r\n\r\n\r\n\/* ==========================================================\r\n   COUNTRY\r\n========================================================== *\/\r\n\r\ncountry.addEventListener(\r\n  \"change\",\r\n  function(){\r\n\r\n    state.value=\"all\";\r\n    type.value=\"all\";\r\n    search.value=\"\";\r\n\r\n\r\n    if(!this.value){\r\n\r\n      state.disabled=true;\r\n      type.disabled=true;\r\n      search.disabled=true;\r\n\r\n      clearMarkers();\r\n\r\n      count.textContent=\"0\";\r\n\r\n      list.innerHTML =\r\n\r\n        '<div class=\"vpd-empty\">' +\r\n\r\n          '<div class=\"vpd-empty-icon\">' +\r\n            '\ud83c\udf0d' +\r\n          '<\/div>' +\r\n\r\n          '<div>' +\r\n            'Select a country to explore ports and ICDs.' +\r\n          '<\/div>' +\r\n\r\n        '<\/div>';\r\n\r\n      map.setView(\r\n        [20,0],\r\n        2\r\n      );\r\n\r\n      return;\r\n\r\n    }\r\n\r\n\r\n    state.disabled=false;\r\n    type.disabled=false;\r\n    search.disabled=false;\r\n\r\n\r\n    loadStates();\r\n\r\n    render();\r\n\r\n  }\r\n);\r\n\r\n\r\n\/* ==========================================================\r\n   FILTER EVENTS\r\n========================================================== *\/\r\n\r\nstate.addEventListener(\r\n  \"change\",\r\n  render\r\n);\r\n\r\ntype.addEventListener(\r\n  \"change\",\r\n  render\r\n);\r\n\r\nsearch.addEventListener(\r\n  \"input\",\r\n  render\r\n);\r\n\r\n\r\n\/* ==========================================================\r\n   WORLD BUTTON\r\n========================================================== *\/\r\n\r\ndocument\r\n  .querySelector(\r\n    \"#vanchile-port-directory #vpd-world\"\r\n  )\r\n  .addEventListener(\r\n    \"click\",\r\n    function(){\r\n\r\n      map.setView(\r\n        [20,0],\r\n        2\r\n      );\r\n\r\n    }\r\n  );\r\n\r\n\r\n\/* ==========================================================\r\n   FULLSCREEN\r\n========================================================== *\/\r\n\r\ndocument\r\n  .querySelector(\r\n    \"#vanchile-port-directory #vpd-fullscreen\"\r\n  )\r\n  .addEventListener(\r\n    \"click\",\r\n    function(){\r\n\r\n      const element =\r\n        document.querySelector(\r\n          \"#vanchile-port-directory #vpd-map\"\r\n        );\r\n\r\n\r\n      if(\r\n        !document.fullscreenElement\r\n      ){\r\n\r\n        if(\r\n          element.requestFullscreen\r\n        ){\r\n\r\n          element.requestFullscreen();\r\n\r\n        }\r\n\r\n      }\r\n      else{\r\n\r\n        document.exitFullscreen();\r\n\r\n      }\r\n\r\n    }\r\n  );\r\n\r\n\r\n\/* ==========================================================\r\n   INITIAL\r\n========================================================== *\/\r\n\r\nloadDatabase();\r\n\r\nsetTimeout(\r\n  function(){\r\n\r\n    map.invalidateSize();\r\n\r\n  },\r\n  500\r\n);\r\n\r\n\r\n})();\r\n<\/script>\r\n\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Country Select Country State \/ Region All States \/ Regions Facility Type All Facilities Sea Port ICD Search Location \ud83d\udd0e Ports &#038; ICDs 0 \ud83c\udf0d Select a country to explore sea ports and ICDs. \ud83c\udf0d \u26f6 Sea Port ICD Need a freight quote? Get competitive shipping rates and logistics support. Request a Quote \u2192<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_acf_changed":false,"_xspeed_no_cache":false,"_xspeed_expiry_hours":0,"footnotes":""},"class_list":["post-2283","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/pages\/2283","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/comments?post=2283"}],"version-history":[{"count":0,"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/pages\/2283\/revisions"}],"wp:attachment":[{"href":"https:\/\/vanchile.com\/wp-json\/wp\/v2\/media?parent=2283"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}