Skip to content
Snippets Groups Projects
Commit 8e12ebd6 authored by M3034's avatar M3034
Browse files

Merge branch 'filter-player-replay' into 'development'

Filter player replay

See merge request !34
parents 059713da e29c702a
No related branches found
No related tags found
2 merge requests!46Development to testing,!34Filter player replay
...@@ -284,3 +284,7 @@ div.login button:hover { ...@@ -284,3 +284,7 @@ div.login button:hover {
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
color: white; color: white;
} }
.filterContainer input:hover {
cursor: pointer;
}
...@@ -54,7 +54,16 @@ export default class GameCard extends React.Component { ...@@ -54,7 +54,16 @@ export default class GameCard extends React.Component {
<Link <Link
to={{ pathname: "/game", search: "?id=" + this.state.gameInfo.id }} to={{ pathname: "/game", search: "?id=" + this.state.gameInfo.id }}
> >
<button type="button">Select</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> </Link>
</div> </div>
); );
......
// https://github.com/linghuam/Leaflet.TrackPlayBack // https://github.com/linghuam/Leaflet.TrackPlayBack
import React from "react"; import React from "react";
import { Link } from "react-router-dom";
import L from "leaflet"; 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/clock";
import "../track-playback/src/leaflet.trackplayback/index"; import "../track-playback/src/leaflet.trackplayback/index";
import "../track-playback/src/control.trackplayback/control.playback"; import "../track-playback/src/control.trackplayback/control.playback";
import "../track-playback/src/control.trackplayback/index"; import "../track-playback/src/control.trackplayback/index";
import DrawGeoJSON from "./DrawGeoJSON";
export default class ReplayMap extends React.Component { export default class ReplayMap extends React.Component {
constructor(props) { constructor(props) {
...@@ -17,81 +16,88 @@ export default class ReplayMap extends React.Component { ...@@ -17,81 +16,88 @@ export default class ReplayMap extends React.Component {
playback: null, playback: null,
// stores player locations from backend // stores player locations from backend
data: null, data: null,
// stores all factions from the game
factions: [],
// stores all drawings from backend // stores all drawings from backend
allGeoJSON: [], allGeoJSON: [],
// stores all active drawings on the map // stores all active drawings on the map
activeGeoJSON: [] activeGeoJSON: []
}; };
this.map = React.createRef();
} }
async componentDidMount() { async componentDidMount() {
await this.fetchPlayerData(); // set gameId to state from URL
//await this.fetchDrawingData(); await this.setState({
//this.tickDrawings(); gameId: await new URL(window.location.href).searchParams.get("id")
this.replay(); });
// 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 () => { fetchPlayerData = async () => {
await fetch( let res = await fetch(
`${ `${process.env.REACT_APP_API_URL}/replay/players/${this.state.gameId}`
process.env.REACT_APP_API_URL );
}/replay/players/314338f9-b0bb-4bf7-9554-769c7b409bce`, if (await res.ok) {
{ return await res.json();
method: "GET" } else {
} alert("Game not found");
) window.document.location.href = "/";
.then(async res => await res.json()) }
.then( };
async res => {
await this.setState({ data: res }); fetchFactions = async () => {
}, let res = await fetch(
// Note: it's important to handle errors here `${process.env.REACT_APP_API_URL}/game/${this.state.gameId}`
// instead of a catch() block so that we don't swallow );
// exceptions from actual bugs in components. if (await res.ok) {
error => { let data = await res.json();
console.log(error); let factions = data.factions.map(faction => {
} return {
); name: faction.factionName,
colour: faction.colour,
active: true
};
});
return await factions;
} else {
alert(res.statusText);
}
}; };
fetchDrawingData = async () => { fetchDrawingData = async () => {
await fetch( let res = await fetch(
`${process.env.REACT_APP_API_URL}/replay/{ `${process.env.REACT_APP_API_URL}/replay/${this.state.gameId}`
"lng": 25.72588, );
"lat": 62.23147 if (await res.ok) {
}`, return await res.json();
{ } else {
method: "GET" alert(res.statusText);
} }
)
.then(async res => await res.json())
.then(
async res => {
await this.setState({ allGeoJSON: res });
},
error => {
console.log(error);
}
);
}; };
tickDrawings = () => { tickDrawings = () => {
let activeDrawings = []; return this.state.allGeoJSON.map(drawing => {
this.state.allGeoJSON.map(drawing => { return drawing[0];
activeDrawings.push(drawing[0]);
this.setState({
activeGeoJSON: {
type: "FeatureCollection",
features: [...activeDrawings]
}
});
}); });
}; };
...@@ -140,6 +146,9 @@ export default class ReplayMap extends React.Component { ...@@ -140,6 +146,9 @@ export default class ReplayMap extends React.Component {
offset: [0, 0], offset: [0, 0],
direction: "top", direction: "top",
permanent: false permanent: false
},
filterOptions: {
factions: this.state.factions
} }
}); });
this.setState({ this.setState({
...@@ -170,6 +179,9 @@ export default class ReplayMap extends React.Component { ...@@ -170,6 +179,9 @@ export default class ReplayMap extends React.Component {
)} )}
</Map> */ </Map> */
<React.Fragment> <React.Fragment>
<Link to="/">
<button>Game selection</button>
</Link>
<div className="map" ref="map" /> <div className="map" ref="map" />
</React.Fragment> </React.Fragment>
); );
......
...@@ -100,12 +100,55 @@ export const TrackPlayBackControl = L.Control.extend({ ...@@ -100,12 +100,55 @@ export const TrackPlayBackControl = L.Control.extend({
"sliderContainer", "sliderContainer",
this._container this._container
); );
this._lineCbx = this._createCheckbox( this._filterContainer = this._createContainer(
"filterContainer",
this._container
);
/* this._lineCbx = this._createCheckbox(
"show trackLine", "show trackLine",
"show-trackLine", "show-trackLine",
this._optionsContainer, this._optionsContainer,
this._showTrackLine 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( this._playBtn = this._createButton(
"play", "play",
...@@ -120,13 +163,13 @@ export const TrackPlayBackControl = L.Control.extend({ ...@@ -120,13 +163,13 @@ export const TrackPlayBackControl = L.Control.extend({
this._restart this._restart
); );
this._slowSpeedBtn = this._createButton( this._slowSpeedBtn = this._createButton(
"slow", "decrease speed",
"btn-slow", "btn-slow",
this._buttonContainer, this._buttonContainer,
this._slow this._slow
); );
this._quickSpeedBtn = this._createButton( this._quickSpeedBtn = this._createButton(
"quick", "increase speed",
"btn-quick", "btn-quick",
this._buttonContainer, this._buttonContainer,
this._quick this._quick
...@@ -187,6 +230,7 @@ export const TrackPlayBackControl = L.Control.extend({ ...@@ -187,6 +230,7 @@ export const TrackPlayBackControl = L.Control.extend({
let inputId = `trackplayback-input-${L.Util.stamp(inputEle)}`; let inputId = `trackplayback-input-${L.Util.stamp(inputEle)}`;
inputEle.setAttribute("type", "checkbox"); inputEle.setAttribute("type", "checkbox");
inputEle.setAttribute("id", inputId); inputEle.setAttribute("id", inputId);
inputEle.checked = true;
let labelEle = L.DomUtil.create("label", "trackplayback-label", divEle); let labelEle = L.DomUtil.create("label", "trackplayback-label", divEle);
labelEle.setAttribute("for", inputId); labelEle.setAttribute("for", inputId);
...@@ -250,6 +294,27 @@ export const TrackPlayBackControl = L.Control.extend({ ...@@ -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() { _play: function() {
let hasClass = L.DomUtil.hasClass(this._playBtn, "btn-stop"); let hasClass = L.DomUtil.hasClass(this._playBtn, "btn-stop");
if (hasClass) { if (hasClass) {
......
...@@ -40,12 +40,19 @@ export const Draw = L.Class.extend({ ...@@ -40,12 +40,19 @@ export const Draw = L.Class.extend({
direction: "top", direction: "top",
permanent: false permanent: false
}, },
filterOptions: {
infantry: true,
recon: true,
mechanized: true,
factions: []
},
initialize: function(map, options) { initialize: function(map, options) {
L.extend(this.trackPointOptions, options.trackPointOptions); L.extend(this.trackPointOptions, options.trackPointOptions);
L.extend(this.trackLineOptions, options.trackLineOptions); L.extend(this.trackLineOptions, options.trackLineOptions);
L.extend(this.targetOptions, options.targetOptions); L.extend(this.targetOptions, options.targetOptions);
L.extend(this.toolTipOptions, options.toolTipOptions); L.extend(this.toolTipOptions, options.toolTipOptions);
L.extend(this.filterOptions, options.filterOptions);
this._showTrackPoint = this.trackPointOptions.isDraw; this._showTrackPoint = this.trackPointOptions.isDraw;
this._showTrackLine = this.trackLineOptions.isDraw; this._showTrackLine = this.trackLineOptions.isDraw;
...@@ -189,12 +196,26 @@ export const Draw = L.Class.extend({ ...@@ -189,12 +196,26 @@ export const Draw = L.Class.extend({
} }
// 画船 // 画船
let targetPoint = trackpoints[trackpoints.length - 1]; let targetPoint = trackpoints[trackpoints.length - 1];
// get info from first trackpoint
let info = trackpoints[0].info; 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); this._drawShipImage(targetPoint, info);
} else {
this._drawShipCanvas(targetPoint);
} }
/* else {
this._drawShipCanvas(targetPoint);
} */
// 画标注信息 // 画标注信息
if (this.targetOptions.showText) { if (this.targetOptions.showText) {
this._drawtxt(`航向:${parseInt(targetPoint.dir)}度`, targetPoint); this._drawtxt(`航向:${parseInt(targetPoint.dir)}度`, targetPoint);
......
import L from 'leaflet' import L from "leaflet";
import { import { Track } from "./track";
Track import { TrackController } from "./trackcontroller";
} from './track' import { Clock } from "./clock";
import { import { Draw } from "./draw";
TrackController import * as Util from "./util";
} from './trackcontroller'
import {
Clock
} from './clock'
import {
Draw
} from './draw'
import * as Util from './util'
/** /**
* single track data * single track data
...@@ -22,110 +14,138 @@ import * as Util from './util' ...@@ -22,110 +14,138 @@ import * as Util from './util'
* [single track data, single track data, single track data] * [single track data, single track data, single track data]
*/ */
export const TrackPlayBack = L.Class.extend({ export const TrackPlayBack = L.Class.extend({
includes: L.Mixin.Events, includes: L.Mixin.Events,
initialize: function (data, map, options = {}) { initialize: function(data, map, options = {}) {
let drawOptions = { let drawOptions = {
trackPointOptions: options.trackPointOptions, trackPointOptions: options.trackPointOptions,
trackLineOptions: options.trackLineOptions, trackLineOptions: options.trackLineOptions,
targetOptions: options.targetOptions, targetOptions: options.targetOptions,
toolTipOptions: options.toolTipOptions toolTipOptions: options.toolTipOptions,
} filterOptions: options.filterOptions
this.tracks = this._initTracks(data) };
this.draw = new Draw(map, drawOptions) this.tracks = this._initTracks(data);
this.trackController = new TrackController(this.tracks, this.draw) this.draw = new Draw(map, drawOptions);
this.clock = new Clock(this.trackController, options.clockOptions) 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 () { slowSpeed: function() {
this.clock.start() this.clock.slowSpeed();
return this return this;
}, },
stop: function () { quickSpeed: function() {
this.clock.stop() this.clock.quickSpeed();
return this return this;
}, },
rePlaying: function () { getSpeed: function() {
this.clock.rePlaying() return this.clock.getSpeed();
return this
}, },
slowSpeed: function () { getCurTime: function() {
this.clock.slowSpeed() return this.clock.getCurTime();
return this
}, },
quickSpeed: function () { getStartTime: function() {
this.clock.quickSpeed() return this.clock.getStartTime();
return this
}, },
getSpeed: function () { getEndTime: function() {
return this.clock.getSpeed() return this.clock.getEndTime();
}, },
getCurTime: function () { isPlaying: function() {
return this.clock.getCurTime() return this.clock.isPlaying();
}, },
getStartTime: function () { setCursor: function(time) {
return this.clock.getStartTime() this.clock.setCursor(time);
return this;
}, },
getEndTime: function () { setSpeed: function(speed) {
return this.clock.getEndTime() this.clock.setSpeed(speed);
return this;
}, },
isPlaying: function () { showTrackPoint: function() {
return this.clock.isPlaying() this.draw.showTrackPoint();
return this;
}, },
setCursor: function (time) { hideTrackPoint: function() {
this.clock.setCursor(time) this.draw.hideTrackPoint();
return this return this;
}, },
setSpeed: function (speed) { showTrackLine: function() {
this.clock.setSpeed(speed) this.draw.showTrackLine();
return this return this;
}, },
showTrackPoint: function () { hideTrackLine: function() {
this.draw.showTrackPoint() this.draw.hideTrackLine();
return this return this;
}, },
hideTrackPoint: function () { // toggles the visibility of infantry units on the map
this.draw.hideTrackPoint() toggleInfantry: function(e) {
return this this.draw.filterOptions.infantry = e;
return this;
}, },
showTrackLine: function () { // toggles the visibility of recon units on the map
this.draw.showTrackLine() toggleRecon: function(e) {
return this 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 () { // pass the factions to control playback to show faction names on the control panel
this.draw.hideTrackLine() passFactions: function() {
return this return this.draw.filterOptions.factions;
}, },
dispose: function () { dispose: function() {
this.clock.off('tick', this._tick) this.clock.off("tick", this._tick);
this.draw.remove() this.draw.remove();
this.tracks = null this.tracks = null;
this.draw = null this.draw = null;
this.trackController = null this.trackController = null;
this.clock = null this.clock = null;
}, },
_tick: function (e) { _tick: function(e) {
this.fire('tick', e) this.fire("tick", e);
}, },
_initTracks: function (data) { _initTracks: function(data) {
let tracks = [] let tracks = [];
if (Util.isArray(data)) { if (Util.isArray(data)) {
if (Util.isArray(data[0])) { if (Util.isArray(data[0])) {
// 多条轨迹 // 多条轨迹
for (let i = 0, len = data.length; i < len; i++) { for (let i = 0, len = data.length; i < len; i++) {
tracks.push(new Track(data[i])) tracks.push(new Track(data[i]));
} }
} else { } else {
// 单条轨迹 // 单条轨迹
tracks.push(new Track(data)) tracks.push(new Track(data));
} }
} }
return tracks return tracks;
} }
}) });
export const trackplayback = function (data, map, options) { export const trackplayback = function(data, map, options) {
return new TrackPlayBack(data, map, options) return new TrackPlayBack(data, map, options);
} };
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment