Load current tour status from server
This commit is contained in:
		
							parent
							
								
									3324a57206
								
							
						
					
					
						commit
						0c1aeebdf7
					
				
							
								
								
									
										468
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										468
									
								
								main.js
									
									
									
									
									
								
							@ -13,257 +13,263 @@ import geojsonPOI from './geo/poi.json'
 | 
			
		||||
 | 
			
		||||
useGeographic();
 | 
			
		||||
 | 
			
		||||
const styles = {
 | 
			
		||||
  lineOrange: new Style({
 | 
			
		||||
    stroke: new Stroke({
 | 
			
		||||
      color: '#FF9900',
 | 
			
		||||
      // lineDash: [8],
 | 
			
		||||
      width: 5,
 | 
			
		||||
    }),
 | 
			
		||||
  }),
 | 
			
		||||
  lineGrey: new Style({
 | 
			
		||||
    stroke: new Stroke({
 | 
			
		||||
      color: '#555555',
 | 
			
		||||
      // lineDash: [8],
 | 
			
		||||
      width: 5,
 | 
			
		||||
    }),
 | 
			
		||||
  }),
 | 
			
		||||
  iconStop: new Style({
 | 
			
		||||
    image: new Icon({
 | 
			
		||||
      anchor: [0.5, 46],
 | 
			
		||||
      anchorXUnits: 'fraction',
 | 
			
		||||
      anchorYUnits: 'pixels',
 | 
			
		||||
      src: '/img/icon.png',
 | 
			
		||||
    }),
 | 
			
		||||
  }),
 | 
			
		||||
  iconVan: new Style({
 | 
			
		||||
    image: new Icon({
 | 
			
		||||
      anchor: [0.5, 16],
 | 
			
		||||
      anchorXUnits: 'fraction',
 | 
			
		||||
      anchorYUnits: 'pixels',
 | 
			
		||||
      src: '/img/van-100px.png',
 | 
			
		||||
    }),
 | 
			
		||||
  }),
 | 
			
		||||
  circleBlack: new Style({
 | 
			
		||||
    image: new CircleStyle({
 | 
			
		||||
      radius: 7,
 | 
			
		||||
      fill: new Fill({color: '#FF9900'}),
 | 
			
		||||
async function main() {
 | 
			
		||||
  const styles = {
 | 
			
		||||
    lineOrange: new Style({
 | 
			
		||||
      stroke: new Stroke({
 | 
			
		||||
        color: 'white',
 | 
			
		||||
        width: 2,
 | 
			
		||||
        color: '#FF9900',
 | 
			
		||||
        // lineDash: [8],
 | 
			
		||||
        width: 5,
 | 
			
		||||
      }),
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Route
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
const lastStageFinished = 2;
 | 
			
		||||
const stagesCompleted = geojsonRoute.features.slice(0, lastStageFinished);
 | 
			
		||||
const stagesAhead = geojsonRoute.features.slice(lastStageFinished);
 | 
			
		||||
const vectorSourceStagesCompleted = new VectorSource();
 | 
			
		||||
const vectorSourceStagesAhead = new VectorSource();
 | 
			
		||||
 | 
			
		||||
for (const stage of stagesCompleted) {
 | 
			
		||||
  vectorSourceStagesCompleted.addFeature(new GeoJSON().readFeature(stage));
 | 
			
		||||
}
 | 
			
		||||
for (const stage of stagesAhead) {
 | 
			
		||||
  vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const stagesCompletedLayer = new VectorLayer({
 | 
			
		||||
  source: vectorSourceStagesCompleted,
 | 
			
		||||
  style: styles.lineOrange
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const stagesAheadLayer = new VectorLayer({
 | 
			
		||||
  source: vectorSourceStagesAhead,
 | 
			
		||||
  style: styles.lineGrey
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Points of Interest
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
const vectorSourcePOI = new VectorSource({
 | 
			
		||||
  features: new GeoJSON().readFeatures(geojsonPOI),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const poiLayer = new VectorLayer({
 | 
			
		||||
  source: vectorSourcePOI,
 | 
			
		||||
  style: styles.circleBlack,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const vectorSourceTrackedPoints = new VectorSource();
 | 
			
		||||
 | 
			
		||||
const vanFeature= new Feature({
 | 
			
		||||
  geometry: new Point([8.918618, 44.407408]),
 | 
			
		||||
  name: 'Support Van',
 | 
			
		||||
  trackable: true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
vectorSourceTrackedPoints.addFeature(vanFeature);
 | 
			
		||||
 | 
			
		||||
const trackedPointsLayer = new VectorLayer({
 | 
			
		||||
  source: vectorSourceTrackedPoints,
 | 
			
		||||
  style: styles.iconVan
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Map initialization
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
const view = new View({
 | 
			
		||||
  center: [10.6, 46.9],
 | 
			
		||||
  zoom: 6.6
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
window.view = view;
 | 
			
		||||
 | 
			
		||||
const map = new Map({
 | 
			
		||||
  target: 'map',
 | 
			
		||||
  layers: [
 | 
			
		||||
    new TileLayer({
 | 
			
		||||
      source: new OSM()
 | 
			
		||||
    }),
 | 
			
		||||
    stagesCompletedLayer,
 | 
			
		||||
    stagesAheadLayer,
 | 
			
		||||
    poiLayer,
 | 
			
		||||
    trackedPointsLayer
 | 
			
		||||
  ],
 | 
			
		||||
  view: view
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Center map on current/next stage
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
setTimeout(() => {
 | 
			
		||||
  const nextStageFeature = new GeoJSON().readFeature(stagesAhead[0]);
 | 
			
		||||
  view.fit(nextStageFeature.getGeometry(), {
 | 
			
		||||
    maxZoom: 10,
 | 
			
		||||
    duration: 1000
 | 
			
		||||
  });
 | 
			
		||||
}, 3000);
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Popups
 | 
			
		||||
//
 | 
			
		||||
const popupEl = document.getElementById('popup');
 | 
			
		||||
 | 
			
		||||
const popup = new Overlay({
 | 
			
		||||
  element: popupEl,
 | 
			
		||||
  positioning: 'bottom-center',
 | 
			
		||||
  stopEvent: false,
 | 
			
		||||
});
 | 
			
		||||
map.addOverlay(popup);
 | 
			
		||||
 | 
			
		||||
let popover;
 | 
			
		||||
function disposePopover() {
 | 
			
		||||
  if (popover) {
 | 
			
		||||
    popover.dispose();
 | 
			
		||||
    popover = undefined;
 | 
			
		||||
    lineGrey: new Style({
 | 
			
		||||
      stroke: new Stroke({
 | 
			
		||||
        color: '#555555',
 | 
			
		||||
        // lineDash: [8],
 | 
			
		||||
        width: 5,
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
    iconStop: new Style({
 | 
			
		||||
      image: new Icon({
 | 
			
		||||
        anchor: [0.5, 46],
 | 
			
		||||
        anchorXUnits: 'fraction',
 | 
			
		||||
        anchorYUnits: 'pixels',
 | 
			
		||||
        src: '/img/icon.png',
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
    iconVan: new Style({
 | 
			
		||||
      image: new Icon({
 | 
			
		||||
        anchor: [0.5, 16],
 | 
			
		||||
        anchorXUnits: 'fraction',
 | 
			
		||||
        anchorYUnits: 'pixels',
 | 
			
		||||
        src: '/img/van-100px.png',
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
    circleBlack: new Style({
 | 
			
		||||
      image: new CircleStyle({
 | 
			
		||||
        radius: 7,
 | 
			
		||||
        fill: new Fill({color: '#FF9900'}),
 | 
			
		||||
        stroke: new Stroke({
 | 
			
		||||
          color: 'white',
 | 
			
		||||
          width: 2,
 | 
			
		||||
        }),
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createPopoverHtml(feature) {
 | 
			
		||||
  const container = document.createElement('div');
 | 
			
		||||
  const title = document.createElement('div');
 | 
			
		||||
  title.textContent = feature.get('name');
 | 
			
		||||
  container.append(title);
 | 
			
		||||
  return container.innerHTML;
 | 
			
		||||
  // if (feature.get('trackable')) {
 | 
			
		||||
  //   const linkParent = document.createElement('div');
 | 
			
		||||
  //   const followLink = document.createElement('a');
 | 
			
		||||
  //   followLink.textContent = 'Follow';
 | 
			
		||||
  //   followLink.href = '#';
 | 
			
		||||
  //   followLink.addEventListener('click', startFollowing(feature, followLink));
 | 
			
		||||
  //   linkParent.append(followLink);
 | 
			
		||||
  //   container.append(linkParent);
 | 
			
		||||
  // }
 | 
			
		||||
}
 | 
			
		||||
  //
 | 
			
		||||
  // Route
 | 
			
		||||
  //
 | 
			
		||||
 | 
			
		||||
// display popup on click
 | 
			
		||||
map.on('click', function (evt) {
 | 
			
		||||
  const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
 | 
			
		||||
    return feature;
 | 
			
		||||
  });
 | 
			
		||||
  disposePopover();
 | 
			
		||||
  if (!feature) {
 | 
			
		||||
    return;
 | 
			
		||||
  const tourStatus = await fetch('https://r2b22.kip.pe/status.json').then(res => res.json());
 | 
			
		||||
 | 
			
		||||
  const lastStageFinished = tourStatus.lastStageFinished;
 | 
			
		||||
  const stagesCompleted = geojsonRoute.features.slice(0, lastStageFinished);
 | 
			
		||||
  const stagesAhead = geojsonRoute.features.slice(lastStageFinished);
 | 
			
		||||
  const vectorSourceStagesCompleted = new VectorSource();
 | 
			
		||||
  const vectorSourceStagesAhead = new VectorSource();
 | 
			
		||||
 | 
			
		||||
  for (const stage of stagesCompleted) {
 | 
			
		||||
    vectorSourceStagesCompleted.addFeature(new GeoJSON().readFeature(stage));
 | 
			
		||||
  }
 | 
			
		||||
  popup.setPosition(evt.coordinate);
 | 
			
		||||
  popover = new bootstrap.Popover(popupEl, {
 | 
			
		||||
    placement: 'top',
 | 
			
		||||
    html: true,
 | 
			
		||||
    content: createPopoverHtml(feature)
 | 
			
		||||
  for (const stage of stagesAhead) {
 | 
			
		||||
    vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const stagesCompletedLayer = new VectorLayer({
 | 
			
		||||
    source: vectorSourceStagesCompleted,
 | 
			
		||||
    style: styles.lineOrange
 | 
			
		||||
  });
 | 
			
		||||
  popover.show();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// change mouse cursor when over marker
 | 
			
		||||
map.on('pointermove', function (evt) {
 | 
			
		||||
  map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel)
 | 
			
		||||
    ? 'pointer'
 | 
			
		||||
    : '';
 | 
			
		||||
});
 | 
			
		||||
  const stagesAheadLayer = new VectorLayer({
 | 
			
		||||
    source: vectorSourceStagesAhead,
 | 
			
		||||
    style: styles.lineGrey
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
// Close the popup when the map is moved
 | 
			
		||||
map.on('movestart', disposePopover);
 | 
			
		||||
  //
 | 
			
		||||
  // Points of Interest
 | 
			
		||||
  //
 | 
			
		||||
 | 
			
		||||
  const vectorSourcePOI = new VectorSource({
 | 
			
		||||
    features: new GeoJSON().readFeatures(geojsonPOI),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Tracking
 | 
			
		||||
//
 | 
			
		||||
  const poiLayer = new VectorLayer({
 | 
			
		||||
    source: vectorSourcePOI,
 | 
			
		||||
    style: styles.circleBlack,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
const updateInterval = 5000;
 | 
			
		||||
let followedFeature = vanFeature;
 | 
			
		||||
let followedZoomed = false;
 | 
			
		||||
// let followedFeature = null;
 | 
			
		||||
  const vectorSourceTrackedPoints = new VectorSource();
 | 
			
		||||
 | 
			
		||||
function startFollowing(feature, followLink) {
 | 
			
		||||
  followedFeature = feature;
 | 
			
		||||
  followLink.textContent = 'Stop following';
 | 
			
		||||
  // followLink.removeEventListener('click', startFollowing);
 | 
			
		||||
  followLink.addEventListener('click', stopFollowing(feature, followLink));
 | 
			
		||||
}
 | 
			
		||||
  const vanFeature= new Feature({
 | 
			
		||||
    geometry: new Point([8.918618, 44.407408]),
 | 
			
		||||
    name: 'Support Van',
 | 
			
		||||
    trackable: true
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
function stopFollowing(feature, followLink) {
 | 
			
		||||
  followedFeature = null;
 | 
			
		||||
  followedZoomed = false;
 | 
			
		||||
  followLink.textContent = 'Stop following';
 | 
			
		||||
  // followLink.removeEventListener('click', stopFollowing);
 | 
			
		||||
  followLink.addEventListener('click', startFollowing(feature, followLink));
 | 
			
		||||
}
 | 
			
		||||
  vectorSourceTrackedPoints.addFeature(vanFeature);
 | 
			
		||||
 | 
			
		||||
function updateData(startInterval=false) {
 | 
			
		||||
  fetch('https://r2b22.kip.pe/last.json')
 | 
			
		||||
    .then(response => response.json())
 | 
			
		||||
    .then(data => {
 | 
			
		||||
      console.log(data);
 | 
			
		||||
      const coords = [data.lon, data.lat];
 | 
			
		||||
      vanFeature.getGeometry().setCoordinates(coords);
 | 
			
		||||
  const trackedPointsLayer = new VectorLayer({
 | 
			
		||||
    source: vectorSourceTrackedPoints,
 | 
			
		||||
    style: styles.iconVan
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
      // let zoomLevel;
 | 
			
		||||
      // if (!followedZoomed) {
 | 
			
		||||
      //   zoomLevel = 13;
 | 
			
		||||
      //   followedZoomed = true;
 | 
			
		||||
      // }
 | 
			
		||||
  //
 | 
			
		||||
  // Map initialization
 | 
			
		||||
  //
 | 
			
		||||
 | 
			
		||||
      // if (followedFeature) {
 | 
			
		||||
      //   view.animate({
 | 
			
		||||
      //     center: followedFeature.getGeometry().getCoordinates(),
 | 
			
		||||
      //     duration: 500,
 | 
			
		||||
      //     zoom: zoomLevel
 | 
			
		||||
      //   });
 | 
			
		||||
      // }
 | 
			
		||||
  const view = new View({
 | 
			
		||||
    center: [10.6, 46.9],
 | 
			
		||||
    zoom: 6.6
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  window.view = view;
 | 
			
		||||
 | 
			
		||||
  const map = new Map({
 | 
			
		||||
    target: 'map',
 | 
			
		||||
    layers: [
 | 
			
		||||
      new TileLayer({
 | 
			
		||||
        source: new OSM()
 | 
			
		||||
      }),
 | 
			
		||||
      stagesCompletedLayer,
 | 
			
		||||
      stagesAheadLayer,
 | 
			
		||||
      poiLayer,
 | 
			
		||||
      trackedPointsLayer
 | 
			
		||||
    ],
 | 
			
		||||
    view: view
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Center map on current/next stage
 | 
			
		||||
  //
 | 
			
		||||
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    const nextStageFeature = new GeoJSON().readFeature(stagesAhead[0]);
 | 
			
		||||
    view.fit(nextStageFeature.getGeometry(), {
 | 
			
		||||
      maxZoom: 10,
 | 
			
		||||
      duration: 1000
 | 
			
		||||
    });
 | 
			
		||||
  }, 3000);
 | 
			
		||||
 | 
			
		||||
  if (startInterval) {
 | 
			
		||||
    setInterval(updateData, updateInterval);
 | 
			
		||||
  //
 | 
			
		||||
  // Popups
 | 
			
		||||
  //
 | 
			
		||||
  const popupEl = document.getElementById('popup');
 | 
			
		||||
 | 
			
		||||
  const popup = new Overlay({
 | 
			
		||||
    element: popupEl,
 | 
			
		||||
    positioning: 'bottom-center',
 | 
			
		||||
    stopEvent: false,
 | 
			
		||||
  });
 | 
			
		||||
  map.addOverlay(popup);
 | 
			
		||||
 | 
			
		||||
  let popover;
 | 
			
		||||
  function disposePopover() {
 | 
			
		||||
    if (popover) {
 | 
			
		||||
      popover.dispose();
 | 
			
		||||
      popover = undefined;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function createPopoverHtml(feature) {
 | 
			
		||||
    const container = document.createElement('div');
 | 
			
		||||
    const title = document.createElement('div');
 | 
			
		||||
    title.textContent = feature.get('name');
 | 
			
		||||
    container.append(title);
 | 
			
		||||
    return container.innerHTML;
 | 
			
		||||
    // if (feature.get('trackable')) {
 | 
			
		||||
    //   const linkParent = document.createElement('div');
 | 
			
		||||
    //   const followLink = document.createElement('a');
 | 
			
		||||
    //   followLink.textContent = 'Follow';
 | 
			
		||||
    //   followLink.href = '#';
 | 
			
		||||
    //   followLink.addEventListener('click', startFollowing(feature, followLink));
 | 
			
		||||
    //   linkParent.append(followLink);
 | 
			
		||||
    //   container.append(linkParent);
 | 
			
		||||
    // }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // display popup on click
 | 
			
		||||
  map.on('click', function (evt) {
 | 
			
		||||
    const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
 | 
			
		||||
      return feature;
 | 
			
		||||
    });
 | 
			
		||||
    disposePopover();
 | 
			
		||||
    if (!feature) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    popup.setPosition(evt.coordinate);
 | 
			
		||||
    popover = new bootstrap.Popover(popupEl, {
 | 
			
		||||
      placement: 'top',
 | 
			
		||||
      html: true,
 | 
			
		||||
      content: createPopoverHtml(feature)
 | 
			
		||||
    });
 | 
			
		||||
    popover.show();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // change mouse cursor when over marker
 | 
			
		||||
  map.on('pointermove', function (evt) {
 | 
			
		||||
    map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel)
 | 
			
		||||
      ? 'pointer'
 | 
			
		||||
      : '';
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Close the popup when the map is moved
 | 
			
		||||
  map.on('movestart', disposePopover);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Tracking
 | 
			
		||||
  //
 | 
			
		||||
 | 
			
		||||
  const updateInterval = 5000;
 | 
			
		||||
  // let followedFeature = vanFeature;
 | 
			
		||||
  // let followedZoomed = false;
 | 
			
		||||
  // let followedFeature = null;
 | 
			
		||||
 | 
			
		||||
  function startFollowing(feature, followLink) {
 | 
			
		||||
    followedFeature = feature;
 | 
			
		||||
    followLink.textContent = 'Stop following';
 | 
			
		||||
    // followLink.removeEventListener('click', startFollowing);
 | 
			
		||||
    followLink.addEventListener('click', stopFollowing(feature, followLink));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function stopFollowing(feature, followLink) {
 | 
			
		||||
    followedFeature = null;
 | 
			
		||||
    followedZoomed = false;
 | 
			
		||||
    followLink.textContent = 'Stop following';
 | 
			
		||||
    // followLink.removeEventListener('click', stopFollowing);
 | 
			
		||||
    followLink.addEventListener('click', startFollowing(feature, followLink));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function updateData(startInterval=false) {
 | 
			
		||||
    fetch('https://r2b22.kip.pe/last.json')
 | 
			
		||||
      .then(response => response.json())
 | 
			
		||||
      .then(data => {
 | 
			
		||||
        console.log(data);
 | 
			
		||||
        const coords = [data.lon, data.lat];
 | 
			
		||||
        vanFeature.getGeometry().setCoordinates(coords);
 | 
			
		||||
 | 
			
		||||
        // let zoomLevel;
 | 
			
		||||
        // if (!followedZoomed) {
 | 
			
		||||
        //   zoomLevel = 13;
 | 
			
		||||
        //   followedZoomed = true;
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        // if (followedFeature) {
 | 
			
		||||
        //   view.animate({
 | 
			
		||||
        //     center: followedFeature.getGeometry().getCoordinates(),
 | 
			
		||||
        //     duration: 500,
 | 
			
		||||
        //     zoom: zoomLevel
 | 
			
		||||
        //   });
 | 
			
		||||
        // }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    if (startInterval) {
 | 
			
		||||
      setInterval(updateData, updateInterval);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateData(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
updateData(true);
 | 
			
		||||
main();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user