diff --git a/src/App.css b/src/App.css
index 88c9891a523a024135a483e54c2cff04b45e3c50..5a477f679bfbf8c30d23e742e4ed96648624cc75 100644
--- a/src/App.css
+++ b/src/App.css
@@ -300,3 +300,7 @@ div.login button:hover {
   background-color: rgba(0, 0, 0, 0.5);
   color: white;
 }
+
+.filterContainer input:hover {
+  cursor: pointer;
+}
diff --git a/src/components/GameCard.js b/src/components/GameCard.js
index 39111e9cd096dbc6549fb806b6235412c8d0d293..18a1e67a7a5287cffa1d189caf2b8d926d171b64 100644
--- a/src/components/GameCard.js
+++ b/src/components/GameCard.js
@@ -54,10 +54,17 @@ export default class GameCard extends React.Component {
         <Link
           to={{ pathname: "/game", search: "?id=" + this.state.gameInfo.id }}
         >
-          <button id={"select" + this.state.gameInfo.name} type="button">
+          <button id={`select${this.state.gameInfo.name}`} type="button">
             Select
           </button>
         </Link>
+        <Link
+          to={{ pathname: "/replay", search: "?id=" + this.state.gameInfo.id }}
+        >
+          <button id={`replay${this.state.gameInfo.name}`} type="button">
+            Replay
+          </button>
+        </Link>
       </div>
     );
   }
diff --git a/src/components/ReplayMap.js b/src/components/ReplayMap.js
index f173ffd93b7bccb67fd61e031800ccb6ac857dbe..1e6305e1fe5e32757d3f78f8884f188aa862153a 100644
--- a/src/components/ReplayMap.js
+++ b/src/components/ReplayMap.js
@@ -1,13 +1,12 @@
 // https://github.com/linghuam/Leaflet.TrackPlayBack
 
 import React from "react";
+import { Link } from "react-router-dom";
 import L from "leaflet";
-import { Map, TileLayer, ZoomControl, Marker, Popup } from "react-leaflet";
 import "../track-playback/src/leaflet.trackplayback/clock";
 import "../track-playback/src/leaflet.trackplayback/index";
 import "../track-playback/src/control.trackplayback/control.playback";
 import "../track-playback/src/control.trackplayback/index";
-import DrawGeoJSON from "./DrawGeoJSON";
 
 export default class ReplayMap extends React.Component {
   constructor(props) {
@@ -17,81 +16,88 @@ export default class ReplayMap extends React.Component {
       playback: null,
       // stores player locations from backend
       data: null,
+      // stores all factions from the game
+      factions: [],
       // stores all drawings from backend
       allGeoJSON: [],
       // stores all active drawings on the map
       activeGeoJSON: []
     };
-    this.map = React.createRef();
   }
 
   async componentDidMount() {
-    await this.fetchPlayerData();
-    //await this.fetchDrawingData();
-    //this.tickDrawings();
-    this.replay();
+    // set gameId to state from URL
+    await this.setState({
+      gameId: await new URL(window.location.href).searchParams.get("id")
+    });
+    // fetch player data with gameId
+    // throws error if game is not found and redirects back to game selection
+    await this.setState({
+      data: await this.fetchPlayerData()
+    });
+    // fetch factions from the game
+    await this.setState({
+      factions: await this.fetchFactions()
+    });
+    // fetch drawings with gameId
+    await this.setState({
+      allGeoJSON: await this.fetchDrawingData()
+    });
+    // WIP, map only active drawings to activeGeoJSON state
+    await this.setState({
+      activeGeoJSON: this.tickDrawings()
+    });
+    // if game was found but game has no replay data, alert the user
+    this.state.data.length > 1
+      ? this.replay()
+      : alert("No replay data was found");
   }
 
-  componentWillReceiveProps(nextProps) {}
-
-  // cloud game a1231e2b-aa29-494d-b687-ea2d48cc23df
-  // local game wimma 314338f9-b0bb-4bf7-9554-769c7b409bce
-  // local game vbox 16977b13-c419-48b4-b7d6-e7620f27bf39
-  // fetch player locations from the game
   fetchPlayerData = async () => {
-    await fetch(
-      `${
-        process.env.REACT_APP_API_URL
-      }/replay/players/314338f9-b0bb-4bf7-9554-769c7b409bce`,
-      {
-        method: "GET"
-      }
-    )
-      .then(async res => await res.json())
-      .then(
-        async res => {
-          await this.setState({ data: res });
-        },
-        // Note: it's important to handle errors here
-        // instead of a catch() block so that we don't swallow
-        // exceptions from actual bugs in components.
-        error => {
-          console.log(error);
-        }
-      );
+    let res = await fetch(
+      `${process.env.REACT_APP_API_URL}/replay/players/${this.state.gameId}`
+    );
+    if (await res.ok) {
+      return await res.json();
+    } else {
+      alert("Game not found");
+      window.document.location.href = "/";
+    }
+  };
+
+  fetchFactions = async () => {
+    let res = await fetch(
+      `${process.env.REACT_APP_API_URL}/game/${this.state.gameId}`
+    );
+    if (await res.ok) {
+      let data = await res.json();
+      let factions = data.factions.map(faction => {
+        return {
+          name: faction.factionName,
+          colour: faction.colour,
+          active: true
+        };
+      });
+      return await factions;
+    } else {
+      alert(res.statusText);
+    }
   };
 
   fetchDrawingData = async () => {
-    await fetch(
-      `${process.env.REACT_APP_API_URL}/replay/{
-		"lng": 25.72588,
-		"lat": 62.23147
-}`,
-      {
-        method: "GET"
-      }
-    )
-      .then(async res => await res.json())
-      .then(
-        async res => {
-          await this.setState({ allGeoJSON: res });
-        },
-        error => {
-          console.log(error);
-        }
-      );
+    let res = await fetch(
+      `${process.env.REACT_APP_API_URL}/replay/${this.state.gameId}`
+    );
+    if (await res.ok) {
+      return await res.json();
+    } else {
+      alert(res.statusText);
+    }
   };
 
   tickDrawings = () => {
-    let activeDrawings = [];
-    this.state.allGeoJSON.map(drawing => {
-      activeDrawings.push(drawing[0]);
-      this.setState({
-        activeGeoJSON: {
-          type: "FeatureCollection",
-          features: [...activeDrawings]
-        }
-      });
+    return this.state.allGeoJSON.map(drawing => {
+      return drawing[0];
     });
   };
 
@@ -140,6 +146,9 @@ export default class ReplayMap extends React.Component {
         offset: [0, 0],
         direction: "top",
         permanent: false
+      },
+      filterOptions: {
+        factions: this.state.factions
       }
     });
     this.setState({
@@ -170,6 +179,9 @@ export default class ReplayMap extends React.Component {
         )}
       </Map> */
       <React.Fragment>
+        <Link to="/">
+          <button>Game selection</button>
+        </Link>
         <div className="map" ref="map" />
       </React.Fragment>
     );
diff --git a/src/track-playback/src/control.trackplayback/control.playback.js b/src/track-playback/src/control.trackplayback/control.playback.js
index 6c6f101980579abf0abab21b9d32c2d4626abca4..18ee33f079993f32cc1b92a2d197f82845cb0776 100644
--- a/src/track-playback/src/control.trackplayback/control.playback.js
+++ b/src/track-playback/src/control.trackplayback/control.playback.js
@@ -100,12 +100,55 @@ export const TrackPlayBackControl = L.Control.extend({
       "sliderContainer",
       this._container
     );
-    this._lineCbx = this._createCheckbox(
+    this._filterContainer = this._createContainer(
+      "filterContainer",
+      this._container
+    );
+    /*     this._lineCbx = this._createCheckbox(
       "show trackLine",
       "show-trackLine",
       this._optionsContainer,
       this._showTrackLine
+    ); */
+    // create checkboxes for filtering persons based on their class
+    this._filterInfantry = this._createCheckbox(
+      "show infantry units",
+      "show-infantry",
+      this._filterContainer,
+      this._showInfantry
+    );
+    this._filterRecon = this._createCheckbox(
+      "show recon units",
+      "show-recon",
+      this._filterContainer,
+      this._showRecon
     );
+    this._filterMechanized = this._createCheckbox(
+      "show mechanized units",
+      "show-mechanized",
+      this._filterContainer,
+      this._showMechanized
+    );
+    // show some text between class based and faction based filtering
+    this._factionText = this._createInfo(
+      "Faction filtering:",
+      "",
+      "faction-text-filter",
+      this._filterContainer
+    );
+    // create checkboxes for filtering persons based on their faction
+    let factions = this.trackPlayBack.passFactions();
+    let factionCheckboxes = [];
+    factions.map(faction => {
+      factionCheckboxes.push(
+        this._createCheckbox(
+          `show ${faction.name}`,
+          `show-${faction.name}`,
+          this._filterContainer,
+          this._showFaction
+        )
+      );
+    });
 
     this._playBtn = this._createButton(
       "play",
@@ -120,13 +163,13 @@ export const TrackPlayBackControl = L.Control.extend({
       this._restart
     );
     this._slowSpeedBtn = this._createButton(
-      "slow",
+      "decrease speed",
       "btn-slow",
       this._buttonContainer,
       this._slow
     );
     this._quickSpeedBtn = this._createButton(
-      "quick",
+      "increase speed",
       "btn-quick",
       this._buttonContainer,
       this._quick
@@ -187,6 +230,7 @@ export const TrackPlayBackControl = L.Control.extend({
     let inputId = `trackplayback-input-${L.Util.stamp(inputEle)}`;
     inputEle.setAttribute("type", "checkbox");
     inputEle.setAttribute("id", inputId);
+    inputEle.checked = true;
 
     let labelEle = L.DomUtil.create("label", "trackplayback-label", divEle);
     labelEle.setAttribute("for", inputId);
@@ -250,6 +294,27 @@ export const TrackPlayBackControl = L.Control.extend({
     }
   },
 
+  _showInfantry(e) {
+    this.trackPlayBack.toggleInfantry(e.target.checked);
+  },
+
+  _showRecon(e) {
+    this.trackPlayBack.toggleRecon(e.target.checked);
+  },
+
+  _showMechanized(e) {
+    this.trackPlayBack.toggleMechanized(e.target.checked);
+  },
+  _showFaction(e) {
+    this.trackPlayBack.toggleFactions(
+      e.target.checked,
+      e.target.parentNode.className.substring(
+        5,
+        e.target.parentNode.className.indexOf(" ")
+      )
+    );
+  },
+
   _play: function() {
     let hasClass = L.DomUtil.hasClass(this._playBtn, "btn-stop");
     if (hasClass) {
diff --git a/src/track-playback/src/leaflet.trackplayback/draw.js b/src/track-playback/src/leaflet.trackplayback/draw.js
index ba05a447d31c1f556076c475519b2401a460d501..9949f45fd090be1efdf684b9fcc556ee0eb66ac6 100644
--- a/src/track-playback/src/leaflet.trackplayback/draw.js
+++ b/src/track-playback/src/leaflet.trackplayback/draw.js
@@ -40,12 +40,19 @@ export const Draw = L.Class.extend({
     direction: "top",
     permanent: false
   },
+  filterOptions: {
+    infantry: true,
+    recon: true,
+    mechanized: true,
+    factions: []
+  },
 
   initialize: function(map, options) {
     L.extend(this.trackPointOptions, options.trackPointOptions);
     L.extend(this.trackLineOptions, options.trackLineOptions);
     L.extend(this.targetOptions, options.targetOptions);
     L.extend(this.toolTipOptions, options.toolTipOptions);
+    L.extend(this.filterOptions, options.filterOptions);
 
     this._showTrackPoint = this.trackPointOptions.isDraw;
     this._showTrackLine = this.trackLineOptions.isDraw;
@@ -189,12 +196,26 @@ export const Draw = L.Class.extend({
     }
     // 画船
     let targetPoint = trackpoints[trackpoints.length - 1];
+    // get info from first trackpoint
     let info = trackpoints[0].info;
-    if (this.targetOptions.useImg && this._targetImg) {
+    let skip = false;
+    // check if faction has been filtered and skip drawing if it is
+    this.filterOptions.factions.forEach(faction => {
+      if (
+        !faction.active &&
+        trackpoints[0].info[1]["value"] === faction.colour
+      ) {
+        skip = true;
+      }
+    });
+
+    // compare icon to filter, draw if true else skip
+    if (!skip && this.filterOptions[info[0]["value"].slice(0, -4)]) {
       this._drawShipImage(targetPoint, info);
-    } else {
-      this._drawShipCanvas(targetPoint);
     }
+    /*     else {
+      this._drawShipCanvas(targetPoint);
+    } */
     // 画标注信息
     if (this.targetOptions.showText) {
       this._drawtxt(`航向:${parseInt(targetPoint.dir)}度`, targetPoint);
diff --git a/src/track-playback/src/leaflet.trackplayback/trackplayback.js b/src/track-playback/src/leaflet.trackplayback/trackplayback.js
index 460102ff1b594c01fad7396cb9517366a04242f8..5aa35aa0cabe74f17ee026b3108bc55bacad4b45 100644
--- a/src/track-playback/src/leaflet.trackplayback/trackplayback.js
+++ b/src/track-playback/src/leaflet.trackplayback/trackplayback.js
@@ -1,18 +1,10 @@
-import L from 'leaflet'
+import L from "leaflet";
 
-import {
-  Track
-} from './track'
-import {
-  TrackController
-} from './trackcontroller'
-import {
-  Clock
-} from './clock'
-import {
-  Draw
-} from './draw'
-import * as Util from './util'
+import { Track } from "./track";
+import { TrackController } from "./trackcontroller";
+import { Clock } from "./clock";
+import { Draw } from "./draw";
+import * as Util from "./util";
 
 /**
  * single track data
@@ -22,110 +14,138 @@ import * as Util from './util'
  * [single track data, single track data, single track data]
  */
 export const TrackPlayBack = L.Class.extend({
-
   includes: L.Mixin.Events,
 
-  initialize: function (data, map, options = {}) {
+  initialize: function(data, map, options = {}) {
     let drawOptions = {
       trackPointOptions: options.trackPointOptions,
       trackLineOptions: options.trackLineOptions,
       targetOptions: options.targetOptions,
-      toolTipOptions: options.toolTipOptions
-    }
-    this.tracks = this._initTracks(data)
-    this.draw = new Draw(map, drawOptions)
-    this.trackController = new TrackController(this.tracks, this.draw)
-    this.clock = new Clock(this.trackController, options.clockOptions)
+      toolTipOptions: options.toolTipOptions,
+      filterOptions: options.filterOptions
+    };
+    this.tracks = this._initTracks(data);
+    this.draw = new Draw(map, drawOptions);
+    this.trackController = new TrackController(this.tracks, this.draw);
+    this.clock = new Clock(this.trackController, options.clockOptions);
 
-    this.clock.on('tick', this._tick, this)
+    this.clock.on("tick", this._tick, this);
+  },
+  start: function() {
+    this.clock.start();
+    return this;
+  },
+  stop: function() {
+    this.clock.stop();
+    return this;
+  },
+  rePlaying: function() {
+    this.clock.rePlaying();
+    return this;
   },
-  start: function () {
-    this.clock.start()
-    return this
+  slowSpeed: function() {
+    this.clock.slowSpeed();
+    return this;
   },
-  stop: function () {
-    this.clock.stop()
-    return this
+  quickSpeed: function() {
+    this.clock.quickSpeed();
+    return this;
   },
-  rePlaying: function () {
-    this.clock.rePlaying()
-    return this
+  getSpeed: function() {
+    return this.clock.getSpeed();
   },
-  slowSpeed: function () {
-    this.clock.slowSpeed()
-    return this
+  getCurTime: function() {
+    return this.clock.getCurTime();
   },
-  quickSpeed: function () {
-    this.clock.quickSpeed()
-    return this
+  getStartTime: function() {
+    return this.clock.getStartTime();
   },
-  getSpeed: function () {
-    return this.clock.getSpeed()
+  getEndTime: function() {
+    return this.clock.getEndTime();
   },
-  getCurTime: function () {
-    return this.clock.getCurTime()
+  isPlaying: function() {
+    return this.clock.isPlaying();
   },
-  getStartTime: function () {
-    return this.clock.getStartTime()
+  setCursor: function(time) {
+    this.clock.setCursor(time);
+    return this;
   },
-  getEndTime: function () {
-    return this.clock.getEndTime()
+  setSpeed: function(speed) {
+    this.clock.setSpeed(speed);
+    return this;
   },
-  isPlaying: function () {
-    return this.clock.isPlaying()
+  showTrackPoint: function() {
+    this.draw.showTrackPoint();
+    return this;
   },
-  setCursor: function (time) {
-    this.clock.setCursor(time)
-    return this
+  hideTrackPoint: function() {
+    this.draw.hideTrackPoint();
+    return this;
   },
-  setSpeed: function (speed) {
-    this.clock.setSpeed(speed)
-    return this
+  showTrackLine: function() {
+    this.draw.showTrackLine();
+    return this;
   },
-  showTrackPoint: function () {
-    this.draw.showTrackPoint()
-    return this
+  hideTrackLine: function() {
+    this.draw.hideTrackLine();
+    return this;
   },
-  hideTrackPoint: function () {
-    this.draw.hideTrackPoint()
-    return this
+  // toggles the visibility of infantry units on the map
+  toggleInfantry: function(e) {
+    this.draw.filterOptions.infantry = e;
+    return this;
   },
-  showTrackLine: function () {
-    this.draw.showTrackLine()
-    return this
+  // toggles the visibility of recon units on the map
+  toggleRecon: function(e) {
+    this.draw.filterOptions.recon = e;
+    return this;
+  },
+  // toggles the visibility of mechanized units on the map
+  toggleMechanized: function(e) {
+    this.draw.filterOptions.mechanized = e;
+    return this;
+  },
+  // toggles the visibility of faction units on the map
+  toggleFactions: function(e, target) {
+    for (let faction of this.draw.filterOptions.factions) {
+      if (faction.name === target) {
+        faction.active = e;
+        break;
+      }
+    }
   },
-  hideTrackLine: function () {
-    this.draw.hideTrackLine()
-    return this
+  // pass the factions to control playback to show faction names on the control panel
+  passFactions: function() {
+    return this.draw.filterOptions.factions;
   },
-  dispose: function () {
-    this.clock.off('tick', this._tick)
-    this.draw.remove()
-    this.tracks = null
-    this.draw = null
-    this.trackController = null
-    this.clock = null
+  dispose: function() {
+    this.clock.off("tick", this._tick);
+    this.draw.remove();
+    this.tracks = null;
+    this.draw = null;
+    this.trackController = null;
+    this.clock = null;
   },
-  _tick: function (e) {
-    this.fire('tick', e)
+  _tick: function(e) {
+    this.fire("tick", e);
   },
-  _initTracks: function (data) {
-    let tracks = []
+  _initTracks: function(data) {
+    let tracks = [];
     if (Util.isArray(data)) {
       if (Util.isArray(data[0])) {
         // 多条轨迹
         for (let i = 0, len = data.length; i < len; i++) {
-          tracks.push(new Track(data[i]))
+          tracks.push(new Track(data[i]));
         }
       } else {
         // 单条轨迹
-        tracks.push(new Track(data))
+        tracks.push(new Track(data));
       }
     }
-    return tracks
+    return tracks;
   }
-})
+});
 
-export const trackplayback = function (data, map, options) {
-  return new TrackPlayBack(data, map, options)
-}
+export const trackplayback = function(data, map, options) {
+  return new TrackPlayBack(data, map, options);
+};