Skip to content

Commit 5929893

Browse files
committed
feat: adds stuff
1 parent e739bb8 commit 5929893

File tree

5 files changed

+493
-18
lines changed

5 files changed

+493
-18
lines changed

packages/web/components/countdown.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div class="count">
33
<div
4-
:class="`fixed top-0 h-3 bg-blue-400 px-5 text-sm ${initial <= 0 || initial >= room.roundTime ? '' : 'transition-all linear duration-1000'}`"
4+
:class="`fixed top-0 h-3 bg-blue-400 text-sm ${initial <= 0 || initial >= room.roundTime ? '' : 'transition-all linear duration-1000'}`"
55
:style="{width: width}"
66
>
77
</div>
@@ -17,11 +17,14 @@ import { Room } from '~/models'
1717
export default class Countdown extends Vue {
1818
@Prop() initial
1919
@Prop() room;
20-
20+
2121
count = null
2222
timer = null
2323
2424
get width(){
25+
if (this.room.timer == 0){
26+
return '0%';
27+
}
2528
return `${100 * ((this.room.timer - 1) / this.room.roundTime)}%`;
2629
}
2730
}
Lines changed: 207 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,217 @@
11
<template>
2-
<div>
3-
I'm map boy
4-
</div>
2+
<div ref="map" style="cursor: pointer !important; width: 100vw; height: 100vh">
3+
4+
</div>
55
</template>
66
<script lang="ts">
77
import Component from 'vue-class-component'
8-
import {Prop, Vue, Watch} from 'vue-property-decorator'
9-
8+
import { Prop, Vue, Watch } from 'vue-property-decorator'
9+
import type { StylePropertySpecification } from "maplibre-gl";
10+
import maplibregl, {
11+
MapMouseEvent,
12+
Marker,
13+
StyleSpecification,
14+
} from "maplibre-gl";
15+
import "maplibre-gl/dist/maplibre-gl.css";
16+
import background from "~/assets/layers/backgroundLayer";
17+
import coastline from "~/assets/layers/coastlineLayer";
18+
import countries from "~/assets/layers/countriesLayer";
19+
import countriesDark from "~/assets/layers/countriesDarkLayer";
20+
import countriesGray from "~/assets/layers/countryLayersGray";
21+
import countryBoundaries from "~/assets/layers/countryBoundariesLayer";
22+
import crimeaLayer from "~/assets/layers/crimeaLayer";
23+
import crimeaLayerGray from "~/assets/layers/crimeaLayerGray";
24+
import crimeaSource from "~/assets/layers/crimeaSource";
25+
import { PINS } from '~/constants/pins';
26+
import { states } from '~/constants/states';
27+
import { Room } from '../../models'
1028
1129
@Component({
1230
methods: {},
1331
components: {
14-
1532
},
1633
})
17-
export default class MapView extends Vue {}
18-
</script>
34+
export default class MapView extends Vue {
35+
map: maplibregl.Map;
36+
marker: maplibregl.Marker;
37+
mapReady;
38+
whenMapReady = new Promise(resolve => {
39+
this.mapReady = resolve;
40+
});
41+
42+
@Prop() room: Room;
43+
44+
created() {
45+
this.whenMapReady = new Promise(resolve => { });
46+
}
47+
48+
mounted() {
49+
const map$: HTMLElement = this.$refs.map as HTMLElement;
50+
this.map = new maplibregl.Map({
51+
container: map$,
52+
style: this.style,
53+
center: [4.550343, 55.665957],
54+
zoom: 1.5,
55+
});
56+
57+
this.marker = new maplibregl.Marker({
58+
draggable: true,
59+
element: this.pin(this.room.player.pin),
60+
})
61+
.setLngLat([8.550343, 55.665957])
62+
.addTo(this.map);
63+
64+
this.map.on("click", event => {
65+
this.marker.setLngLat(event.lngLat);
66+
});
67+
this.map.on("load", () => this.mapReady());
68+
}
69+
70+
fadeMapColors() {
71+
this.whenMapReady.then(() => {
72+
this.map.setStyle(this.style as StyleSpecification, {
73+
74+
});
75+
});
76+
}
77+
78+
showCountryShape() {
79+
this.whenMapReady.then(() => {
80+
if (!this.room?.country?.shape) {
81+
return;
82+
}
83+
84+
const geojson = JSON.parse(this.room.country.shape);
85+
const source = this.map.addSource('subject', {
86+
'type': 'geojson',
87+
'data': geojson
88+
});
89+
this.map.addLayer({
90+
'id': 'subject-fill',
91+
'type': 'fill',
92+
'source': 'subject',
93+
'layout': {},
94+
'paint': {
95+
'fill-color': '#4AB63B',
96+
'fill-opacity': 0.7
97+
}
98+
});
99+
100+
this.map.addLayer({
101+
'id': 'subject-border',
102+
'type': 'line',
103+
'source': 'subject',
104+
'layout': {},
105+
'paint': {
106+
'line-color': '#4AB63B',
107+
'line-width': 5,
108+
'line-opacity': 1
109+
}
110+
});
111+
});
112+
}
113+
114+
showCountryMarker() {
115+
this.whenMapReady.then(() => {
116+
this.countryMarker = new maplibregl.Marker()
117+
.setLngLat([this.room.country.lat, this.room.country.lng])
118+
.addTo(this.map);
119+
});
120+
}
121+
122+
showDistanceLines() {
123+
this.whenMapReady.then(() => {
124+
// Coordinates for the polyline from point A to point B
125+
const coordinates = [
126+
this.marker.getLngLat().toArray(), // Point A (Longitude, Latitude)
127+
[this.room.country.lat, this.room.country.lng] // Point B (Longitude, Latitude)
128+
];
129+
130+
// Add a GeoJSON source with the polyline data
131+
this.map.addSource('line', {
132+
'type': 'geojson',
133+
'data': {
134+
'type': 'Feature',
135+
'geometry': {
136+
'type': 'LineString',
137+
'coordinates': coordinates
138+
}
139+
}
140+
});
141+
142+
// Add a line layer to display the polyline
143+
this.map.addLayer({
144+
'id': 'line-layer',
145+
'type': 'line',
146+
'source': 'line',
147+
'layout': {
148+
'line-cap': 'round',
149+
'line-join': 'round'
150+
},
151+
'paint': {
152+
'line-color': '#FF0000',
153+
'line-width': 4,
154+
'line-opacity': 0.8
155+
}
156+
});
157+
158+
});
159+
}
160+
161+
@Watch('room.state', { immediate: true })
162+
async vote(newState) {
163+
switch (newState) {
164+
case states.PARTY_ROUND_END:
165+
case states.ROUND_END:
166+
//this.fadeMapColors();
167+
this.showCountryShape();
168+
this.showCountryMarker();
169+
this.showDistanceLines();
170+
break;
171+
default:
172+
}
173+
}
174+
175+
pin(color) {
176+
const pin = PINS[this.room.player.pin];
177+
const element = document.createElement("div");
178+
element.innerHTML = `<img style="width: 52px; height: 52px; position: relative; left: 4px; top: -26px;" src=${pin} />`;
179+
return element;
180+
}
181+
182+
get style() {
183+
const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
184+
return {
185+
name: "MapLibre",
186+
zoom: 0.8619833357855968,
187+
pitch: 0,
188+
center: [17.65431710431244, 32.954120326746775],
189+
glyphs: `/font/{fontstack}/{range}.pbf`,
190+
layers: [
191+
background,
192+
coastline,
193+
isDarkMode ? countriesDark : countries,
194+
countryBoundaries,
195+
crimeaLayer
196+
],
197+
bearing: 0,
198+
sources: {
199+
maplibre: {
200+
url: `/tiles/tiles.json`,
201+
type: "vector",
202+
},
203+
crimea: crimeaSource,
204+
},
205+
version: 8,
206+
metadata: {
207+
208+
},
209+
};
210+
}
211+
}
212+
</script>
213+
<style>
214+
.maplibregl-canvas {
215+
cursor: crosshair !important;
216+
}
217+
</style>

packages/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"leaflet": "^1.7.1",
3131
"lil-gui": "^0.19.2",
3232
"lodash": "^4.17.21",
33+
"maplibre-gl": "^4.5.0",
3334
"numeral": "^2.0.6",
3435
"nuxt": "2.15.8",
3536
"nuxt-i18n": "^6.22.3",

packages/web/pages/play/_id/index.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
room && room.state === states.ROUND_END ? 'gray-map' : ''
66
}`"
77
>
8+
<!-- <MapView v-if="room && room.player" :room="room" />-->
89
<GameMap :room="room" />
910
<template v-if="room">
1011
<RoundPrepareDialog
@@ -46,8 +47,8 @@
4647
<GameEndDialog :room="room" v-if="room.state === states.GAME_END" />
4748

4849
<Countdown v-if="room.state === states.ROUND_START" :room="room" :initial="room.timer" />
49-
50-
50+
51+
5152
<Overlay
5253
:room="room"
5354
position="topleft"
@@ -92,6 +93,7 @@ import MultiplayerScoreBoardDialog from '~/components/dialogs/multiplayer-score-
9293
import { states } from '~/constants/states'
9394
import GameMap from '~/components/game/GameMap.vue'
9495
import {CONTINUE_ROUND_MESSAGE, VOTE_MESSAGE} from "~/constants/messages";
96+
import MapView from '~/components/game/MapView.vue'
9597
9698
@Component({
9799
layout: 'play',
@@ -108,6 +110,7 @@ import {CONTINUE_ROUND_MESSAGE, VOTE_MESSAGE} from "~/constants/messages";
108110
MultiplayerScoreBoardDialog,
109111
Countdown,
110112
ScoreBoardOverlay,
113+
MapView,
111114
},
112115
})
113116
export default class Index extends Vue {

0 commit comments

Comments
 (0)