|
@@ -1,38 +1,54 @@
|
|
|
import React, { useRef, useEffect } from "react";
|
|
|
import styled from "styled-components";
|
|
|
+import { useLastRound, usePlayerName, dispatch } from "../../../domain/gameStore";
|
|
|
import useMap from "../../../hooks/useMap";
|
|
|
-import { useLastRound } from "../../../domain/gameStore";
|
|
|
-import flag from "../../../assets/checkered-flag.svg";
|
|
|
import usePlayerScores from "../../../hooks/usePlayerScores";
|
|
|
+import useRoundInfo from "../../../hooks/useRoundInfo";
|
|
|
+import DelayedButton from "../../util/DelayedButton";
|
|
|
+import Button from "../../util/Button";
|
|
|
/* global google */
|
|
|
|
|
|
|
|
|
const Container = styled.div`
|
|
|
- flex: 1;
|
|
|
+`
|
|
|
+
|
|
|
+const SummaryDiv = styled.div`
|
|
|
+ position: absolute;
|
|
|
display: flex;
|
|
|
flex-flow: column nowrap;
|
|
|
- justify-content: space-around;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- @media only screen and (min-width: 600px) {
|
|
|
- flex-flow: row nowrap;
|
|
|
- }
|
|
|
+ background-color: #333;
|
|
|
+ z-index: 1;
|
|
|
+ bottom: 16px;
|
|
|
+ right: 8px;
|
|
|
+ padding: 8px;
|
|
|
`
|
|
|
|
|
|
+const ScoreSpan = styled.span`
|
|
|
+ padding-bottom: 2px;
|
|
|
+`;
|
|
|
+
|
|
|
const MapDiv = styled.div`
|
|
|
- height: 50%;
|
|
|
+ position: absolute;
|
|
|
+ height: 100%;
|
|
|
width: 100%;
|
|
|
+`
|
|
|
|
|
|
- @media only screen and (min-width: 600px) {
|
|
|
- width: 50%;
|
|
|
- }
|
|
|
+const FinishedButton = styled(Button)`
|
|
|
+ margin-top: 5px;
|
|
|
+ padding: 1em;
|
|
|
+`
|
|
|
+
|
|
|
+const NextButton = styled(DelayedButton)`
|
|
|
+ margin-top: 5px;
|
|
|
+ padding: 1em;
|
|
|
`
|
|
|
|
|
|
const flagIcon = {
|
|
|
- url: flag,
|
|
|
- scaledSize: new google.maps.Size(32, 32),
|
|
|
- origin: new google.maps.Point(0, 0),
|
|
|
- anchor: new google.maps.Point(4, 36),
|
|
|
+ path: "M466.515 66.928C487.731 57.074 512 72.551 512 95.944v243.1c0 10.526-5.161 20.407-13.843 26.358-35.837 24.564-74.335 40.858-122.505 40.858-67.373 0-111.63-34.783-165.217-34.783-50.853 0-86.124 10.058-114.435 22.122V488c0 13.255-10.745 24-24 24H56c-13.255 0-24-10.745-24-24V101.945C17.497 91.825 8 75.026 8 56 8 24.296 34.345-1.254 66.338.048c28.468 1.158 51.779 23.968 53.551 52.404.52 8.342-.81 16.31-3.586 23.562C137.039 68.384 159.393 64 184.348 64c67.373 0 111.63 34.783 165.217 34.783 40.496 0 82.612-15.906 116.95-31.855zM96 134.63v70.49c29-10.67 51.18-17.83 73.6-20.91v-71.57c-23.5 2.17-40.44 9.79-73.6 21.99zm220.8 9.19c-26.417-4.672-49.886-13.979-73.6-21.34v67.42c24.175 6.706 47.566 16.444 73.6 22.31v-68.39zm-147.2 40.39v70.04c32.796-2.978 53.91-.635 73.6 3.8V189.9c-25.247-7.035-46.581-9.423-73.6-5.69zm73.6 142.23c26.338 4.652 49.732 13.927 73.6 21.34v-67.41c-24.277-6.746-47.54-16.45-73.6-22.32v68.39zM96 342.1c23.62-8.39 47.79-13.84 73.6-16.56v-71.29c-26.11 2.35-47.36 8.04-73.6 17.36v70.49zm368-221.6c-21.3 8.85-46.59 17.64-73.6 22.47v71.91c27.31-4.36 50.03-14.1 73.6-23.89V120.5zm0 209.96v-70.49c-22.19 14.2-48.78 22.61-73.6 26.02v71.58c25.07-2.38 48.49-11.04 73.6-27.11zM316.8 212.21v68.16c25.664 7.134 46.616 9.342 73.6 5.62v-71.11c-25.999 4.187-49.943 2.676-73.6-2.67z",
|
|
|
+ fillOpacity: 1.0,
|
|
|
+ fillColor: "#000000",
|
|
|
+ scale: 0.075,
|
|
|
+ anchor: new google.maps.Point(16, 512),
|
|
|
};
|
|
|
|
|
|
const questionSymbol = color => ({
|
|
@@ -40,7 +56,7 @@ const questionSymbol = color => ({
|
|
|
fillOpacity: 1.0,
|
|
|
fillColor: color,
|
|
|
scale: 1,
|
|
|
- anchor: new google.maps.Point(24, 36),
|
|
|
+ anchor: new google.maps.Point(32, 40),
|
|
|
})
|
|
|
|
|
|
const lineSettings = color => ({
|
|
@@ -74,25 +90,25 @@ const makeMarker = (map, position, title, icon) => {
|
|
|
return marker;
|
|
|
}
|
|
|
|
|
|
+// logic adapted from How to Generate Random Colors Programmatically by Martin Ankerl
|
|
|
+// https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
|
|
const goldenRatioConj = 0.618033988749895;
|
|
|
let h = 0;
|
|
|
const nextColor = () => {
|
|
|
h += goldenRatioConj;
|
|
|
h %= 1;
|
|
|
- const s = 0.5;
|
|
|
- const v = 0.9;
|
|
|
- const h_i = Math.floor(h*6)
|
|
|
- const f = h*6 - h_i
|
|
|
- const p = v * (1 - s)
|
|
|
- const q = v * (1 - f*s)
|
|
|
- const t = v * (1 - (1 - f) * s)
|
|
|
+ const h6 = h * 6;
|
|
|
+ const h_i = Math.floor(h6);
|
|
|
+ const f = 0.45 * (h6 - h_i);
|
|
|
+ const q = 0.9 - f;
|
|
|
+ const t = f + 0.45;
|
|
|
return "#" + ([
|
|
|
- [v, t, p],
|
|
|
- [q, v, p],
|
|
|
- [p, v, t],
|
|
|
- [p, q, v],
|
|
|
- [t, p, v],
|
|
|
- [v, p, q],
|
|
|
+ [0.9, t, 0.45],
|
|
|
+ [q, 0.9, 0.45],
|
|
|
+ [0.45, 0.9, t],
|
|
|
+ [0.45, q, 0.9],
|
|
|
+ [t, 0.45, 0.9],
|
|
|
+ [0.9, 0.45, q],
|
|
|
])[h_i].map(component => {
|
|
|
const converted = Math.floor(component * 256).toString(16);
|
|
|
if (converted.length === 1) {
|
|
@@ -106,7 +122,7 @@ const playerColors = {};
|
|
|
|
|
|
export default () => {
|
|
|
// get the info about the last round
|
|
|
- const { roundNum, targetPoint } = useLastRound();
|
|
|
+ const { roundNum, targetPoint, score, totalScore } = useLastRound();
|
|
|
|
|
|
// draw the map
|
|
|
// TODO dynamically determine this zoom level?
|
|
@@ -119,6 +135,9 @@ export default () => {
|
|
|
return () => targetMarker.setMap(null);
|
|
|
}, [mapRef, targetPoint]);
|
|
|
|
|
|
+ // get the player's name
|
|
|
+ const playerName = usePlayerName();
|
|
|
+
|
|
|
// live update the player scores
|
|
|
const players = usePlayerScores()
|
|
|
?.filter(({ guesses }) => guesses[roundNum] && guesses[roundNum].score);
|
|
@@ -127,7 +146,7 @@ export default () => {
|
|
|
const drawings = [];
|
|
|
players.forEach(({ name, guesses }) => {
|
|
|
const { lat, lng, score } = guesses[roundNum]
|
|
|
- const color = playerColors[name] ?? nextColor();
|
|
|
+ const color = playerName === name ? "#000000" : playerColors[name] ?? nextColor();
|
|
|
playerColors[name] = color;
|
|
|
const selectedPoint = { lat, lng };
|
|
|
|
|
@@ -142,11 +161,27 @@ export default () => {
|
|
|
drawings.push(line);
|
|
|
});
|
|
|
return () => drawings.forEach((drawing) => drawing.setMap(null));
|
|
|
- }, [players, mapRef, targetPoint, roundNum]);
|
|
|
+ }, [players, mapRef, targetPoint, roundNum, playerName]);
|
|
|
+
|
|
|
+ // whether or not the game is done
|
|
|
+ const [gameFinished] = useRoundInfo()
|
|
|
|
|
|
return (
|
|
|
<Container>
|
|
|
<MapDiv ref={mapDivRef} />
|
|
|
+ <SummaryDiv>
|
|
|
+ <ScoreSpan>Score for Round {roundNum}: {score}</ScoreSpan>
|
|
|
+ <ScoreSpan>Running Total: {totalScore}</ScoreSpan>
|
|
|
+ {
|
|
|
+ gameFinished
|
|
|
+ ? <FinishedButton onClick={dispatch.startRound}>
|
|
|
+ View Summary
|
|
|
+ </FinishedButton>
|
|
|
+ : <NextButton onEnd={dispatch.startRound} countDownFormatter={rem => `Click to cancel, ${rem}s...`}>
|
|
|
+ Next Round
|
|
|
+ </NextButton>
|
|
|
+ }
|
|
|
+ </SummaryDiv>
|
|
|
</Container>
|
|
|
);
|
|
|
};
|