diff --git a/src/components/ReplayConfig.js b/src/components/ReplayConfig.js new file mode 100644 index 0000000000000000000000000000000000000000..9eea9de7fcf39dd7eea0bce866e486632b7866ef --- /dev/null +++ b/src/components/ReplayConfig.js @@ -0,0 +1,45 @@ +import React from "react"; + +var options = { + trackPointOptions: { + // whether to draw track point + isDraw: true, + // whether to use canvas to draw it, if false, use leaflet api `L.circleMarker` + useCanvas: false, + stroke: true, + color: "#000000", + fill: true, + fillColor: "rgba(0,0,0,0)", + opacity: 0, + radius: 12 + }, + targetOptions: { + // whether to use an image to display target, if false, the program provides a default + useImg: true, + // if useImg is true, provide the imgUrl + imgUrl: "../light-infantry.svg", + // the width of target, unit: px + width: 60, + // the height of target, unit: px + height: 40, + // the stroke color of target, effective when useImg set false + color: "#00f", + // the fill color of target, effective when useImg set false + fillColor: "#9FD12D" + }, + clockOptions: { + // the default speed + // caculate method: fpstime * Math.pow(2, speed - 1) + // fpstime is the two frame time difference + speed: 10, + // the max speed + maxSpeed: 100 + }, + toolTipOptions: { + offset: [0, 0], + direction: "top", + permanent: false + } +}; + +export default options; diff --git a/src/components/ReplayMap.js b/src/components/ReplayMap.js index 2a16aeb726086efcf62f2b866d61cb8024dad537..ec30ce883a4ef3fdcbed4bfc925c2f0d2951e63a 100644 --- a/src/components/ReplayMap.js +++ b/src/components/ReplayMap.js @@ -7,13 +7,14 @@ 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 options from "./ReplayConfig"; export default class ReplayMap extends React.Component { constructor(props) { super(props); this.state = { - // stores the playback object - playback: null, + // stores game's initial location + location: [62.3, 25.7], // stores player locations from backend players: [], // stores all factions from the game @@ -21,9 +22,7 @@ export default class ReplayMap extends React.Component { // stores all scores from the game scores: [], // stores all drawings from backend - allGeoJSON: [], - // stores all active drawings on the map - activeGeoJSON: [] + drawings: [] }; } @@ -35,9 +34,11 @@ export default class ReplayMap extends React.Component { // fetch all data and set it to state let replaydata = await this.fetchReplayData(); await this.setState({ + location: replaydata.location, players: replaydata.players, factions: replaydata.factions, - scores: replaydata.scores + scores: replaydata.scores, + drawings: replaydata.drawings }); replaydata ? this.replay() : alert("No replay data was found"); } @@ -61,85 +62,26 @@ export default class ReplayMap extends React.Component { }; replay = () => { - this.map = L.map(this.refs.map).setView([62.3, 25.7], 15); + // create a map for the replay, setView to game's center cords + this.map = L.map(this.refs.map).setView( + this.state.location || [62.3, 25.7], + 14 + ); L.tileLayer("https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg", { attribution: '© <a href="https://www.maanmittauslaitos.fi/">Maanmittauslaitos</a>' }).addTo(this.map); - this.trackplayback = new L.TrackPlayBack(this.state.players, this.map, { - trackPointOptions: { - // whether to draw track point - isDraw: true, - // whether to use canvas to draw it, if false, use leaflet api `L.circleMarker` - useCanvas: false, - stroke: true, - color: "#000000", - fill: true, - fillColor: "rgba(0,0,0,0)", - opacity: 0, - radius: 12 - }, - targetOptions: { - // whether to use an image to display target, if false, the program provides a default - useImg: true, - // if useImg is true, provide the imgUrl - imgUrl: "../light-infantry.svg", - // the width of target, unit: px - width: 60, - // the height of target, unit: px - height: 40, - // the stroke color of target, effective when useImg set false - color: "#00f", - // the fill color of target, effective when useImg set false - fillColor: "#9FD12D" - }, - clockOptions: { - // the default speed - // caculate method: fpstime * Math.pow(2, speed - 1) - // fpstime is the two frame time difference - speed: 10, - // the max speed - maxSpeed: 100 - }, - toolTipOptions: { - offset: [0, 0], - direction: "top", - permanent: false - }, - filterOptions: { - factions: this.state.factions - }, - scoreOptions: { - scores: this.state.scores - } - }); - this.setState({ - playback: this.trackplayback - }); - this.trackplaybackControl = L.trackplaybackcontrol(this.trackplayback); + // import options from ReplayConfig.js + this.trackplayback = new L.TrackPlayBack(this.state, this.map, options); + this.trackplaybackControl = L.trackplaybackcontrol( + this.trackplayback, + this.map + ); this.trackplaybackControl.addTo(this.map); }; render() { return ( - /* <Map - className="map" - ref={this.map} - center={[62.3, 25.7]} - zoom={15} - minZoom="7" - maxZoom="17" - zoomControl={false} - > - <TileLayer - attribution='© <a href="https://www.maanmittauslaitos.fi/">Maanmittauslaitos</a>' - url={"https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"} - /> - <ZoomControl position="topright" /> - {this.state.activeGeoJSON.features && ( - <DrawGeoJSON geoJSONLayer={this.state.activeGeoJSON} /> - )} - </Map> */ <React.Fragment> <Link to="/"> <button>Game selection</button> diff --git a/src/track-playback/src/control.trackplayback/control.playback.js b/src/track-playback/src/control.trackplayback/control.playback.js index 2d2e9f5ddd0da2e61f9ed56fe45e862ac53f84a7..56d311958ee2b2c5fdb1f28a5ccc6c5bcce7c51f 100644 --- a/src/track-playback/src/control.trackplayback/control.playback.js +++ b/src/track-playback/src/control.trackplayback/control.playback.js @@ -9,10 +9,71 @@ export const TrackPlayBackControl = L.Control.extend({ autoPlay: false }, - initialize: function(trackplayback, options) { + initialize: function(trackplayback, map, options) { + this.map = map; L.Control.prototype.initialize.call(this, options); this.trackPlayBack = trackplayback; this.trackPlayBack.on("tick", this._tickCallback, this); + this.leafletDrawings = []; + }, + + // absolutely disgusting, never use geojson + // init object to pass drawing data to right function + _drawFunction: function(data) { + // create leaflet objects + var createMarker = data => { + data.geometry.coordinates = [ + data.geometry.coordinates[1], + data.geometry.coordinates[0] + ]; + return L.marker(data.geometry.coordinates).addTo(this.map); + }; + var createPolyline = data => { + data.geometry.coordinates = data.geometry.coordinates.map(cords => { + return [cords[1], cords[0]]; + }); + return L.polyline(data.geometry.coordinates, { + color: data.properties.color + }).addTo(this.map); + }; + var createPolygon = data => { + // geoJSON has lat lng wrong way so turn them around + data.geometry.coordinates = data.geometry.coordinates[0].map(cords => { + return [cords[1], cords[0]]; + }); + return L.polygon(data.geometry.coordinates, { + color: data.properties.color + }).addTo(this.map); + }; + var createRectangle = data => { + return L.rectangle(data.geometry.coordinates, { + color: data.properties.color + }).addTo(this.map); + }; + var createCircle = data => { + data.geometry.coordinates = [ + data.geometry.coordinates[1], + data.geometry.coordinates[0] + ]; + return L.circle(data.geometry.coordinates, { + radius: data.properties.radius + }).addTo(this.map); + }; + // handle faulty cords + if (!data.geometry.coordinates[0][0] && !data.geometry.type === "Point") { + return null; + } + if (data.geometry.type === "Point" && !data.properties.radius) { + data.geometry.type = "Marker"; + } + var obj = { + Marker: createMarker, + LineString: createPolyline, + Polygon: createPolygon, + Rectangle: createRectangle, + Point: createCircle + }; + return obj[data.geometry.type](data); }, onAdd: function(map) { @@ -379,11 +440,6 @@ export const TrackPlayBackControl = L.Control.extend({ // 更新时间 let time = this.getTimeStrFromUnix(e.time); this._infoCurTime.innerHTML = time; - // tick scores - for (let i = 0; i < this._factionScoreboxes.length; i++) { - this._factionScoreboxes[i].innerHTML = this.trackPlayBack.passScores(i); - } - // 更新时间轴 this._slider.value = e.time; // æ’放结æŸåŽæ”¹å˜æ’æ”¾æŒ‰é’®æ ·å¼ if (e.time >= this.trackPlayBack.getEndTime()) { @@ -392,9 +448,37 @@ export const TrackPlayBackControl = L.Control.extend({ this._playBtn.setAttribute("title", "play"); this.trackPlayBack.stop(); } + // tick scores + for (let i = 0; i < this._factionScoreboxes.length; i++) { + this._factionScoreboxes[i].innerHTML = this.trackPlayBack.passScores(i); + } + // tick drawings + let drawings = this.trackPlayBack.passDrawings(); + for (let i = 0; i < drawings.length; i++) { + // skip if undefined + if (!drawings[i] && this.leafletDrawings[i]) { + this.map.removeLayer(this.leafletDrawings[i]); + this.leafletDrawings[i] = null; + return; + } + if (!drawings[i]) return; + // remove if it's not active + if (!drawings[i].drawingIsActive && this.leafletDrawings[i]) { + this.map.removeLayer(this.leafletDrawings[i]); + this.leafletDrawings[i] = null; + return; + } + // else draw the marker if it's not drawn + if (drawings[i].drawingIsActive && !this.leafletDrawings[i]) { + this.leafletDrawings[i] = this._drawFunction(drawings[i].data); + console.log(this.leafletDrawings[i]); + } + } + // + // 更新时间轴 } }); -export const trackplaybackcontrol = function(trackplayback, options) { - return new TrackPlayBackControl(trackplayback, options); +export const trackplaybackcontrol = function(trackplayback, map, options) { + return new TrackPlayBackControl(trackplayback, map, options); }; diff --git a/src/track-playback/src/leaflet.trackplayback/trackcontroller.js b/src/track-playback/src/leaflet.trackplayback/trackcontroller.js index c2d53d9a230b2ae1e81fddc2c3d2cbba02470af0..99596410b3f27d226e8e00e450190fe1bd2968ed 100644 --- a/src/track-playback/src/leaflet.trackplayback/trackcontroller.js +++ b/src/track-playback/src/leaflet.trackplayback/trackcontroller.js @@ -8,12 +8,14 @@ import { Track } from "./track"; * 控制轨迹和绘制 */ export const TrackController = L.Class.extend({ - initialize: function(tracks = [], draw, allScores, options) { + initialize: function(data, draw, options) { L.setOptions(this, options); - this._activeScores = [0, 0]; - this._tracks = []; - this._scores = allScores.scores; - this.addTrack(tracks); + this._activeScores = []; + this._activeDrawings = []; + this._tracks = data.tracks; + this._scores = data.scores; + this._drawings = data.drawings; + this.addTrack(data.tracks || []); this._draw = draw; @@ -45,11 +47,13 @@ export const TrackController = L.Class.extend({ drawTracksByTime: function(time) { this._draw.clear(); + // draw player locations for (let i = 0, len = this._tracks.length; i < len; i++) { let track = this._tracks[i]; let tps = track.getTrackPointsBeforeTime(time); if (tps && tps.length) this._draw.drawTrack(tps); } + // add scores to counter for (let i = 0; i < this._scores.length; i++) { let newScore = 0; let scores = this._scores[i]; @@ -60,6 +64,16 @@ export const TrackController = L.Class.extend({ } this._activeScores[i] = newScore; } + // draw mapdrawings to map + for (let i = 0; i < this._drawings.length; i++) { + let drawing = null; + for (let j = 0; j < this._drawings[i].length; j++) { + if (this._drawings[i][j].timestamp < time) { + drawing = this._drawings[i][j]; + } + } + this._activeDrawings[i] = drawing; + } }, _updateTime: function() { diff --git a/src/track-playback/src/leaflet.trackplayback/trackplayback.js b/src/track-playback/src/leaflet.trackplayback/trackplayback.js index c26733cbfdc9f6056af2ca68b39e62d5de358654..d707967afe0cb3fa5cb76daa9107924f730548d0 100644 --- a/src/track-playback/src/leaflet.trackplayback/trackplayback.js +++ b/src/track-playback/src/leaflet.trackplayback/trackplayback.js @@ -22,15 +22,17 @@ export const TrackPlayBack = L.Class.extend({ trackLineOptions: options.trackLineOptions, targetOptions: options.targetOptions, toolTipOptions: options.toolTipOptions, - filterOptions: options.filterOptions - //scoreOptions: options.scoreOptions + filterOptions: { factions: data.factions } }; - this.tracks = this._initTracks(data); + this.tracks = this._initTracks(data.players); this.draw = new Draw(map, drawOptions); this.trackController = new TrackController( - this.tracks, - this.draw, - options.scoreOptions + { + tracks: this.tracks, + scores: data.scores, + drawings: data.drawings + }, + this.draw ); this.clock = new Clock(this.trackController, options.clockOptions); @@ -123,9 +125,14 @@ export const TrackPlayBack = L.Class.extend({ passFactions: function() { return this.draw.filterOptions.factions; }, + // pass current scores to control panel passScores: function(i) { return this.trackController._activeScores[i]; }, + // pass current drawings to control panel + passDrawings: function() { + return this.trackController._activeDrawings; + }, dispose: function() { this.clock.off("tick", this._tick); this.draw.remove(); @@ -155,5 +162,5 @@ export const TrackPlayBack = L.Class.extend({ }); export const trackplayback = function(data, map, options) { - return new TrackPlayBack(data, map, options); + return new TrackPlayBack(data.players, map, options); };