11<template >
2- <div >
3- I'm map boy
4- </div >
2+ <div ref = " map " style = " cursor : pointer !important ; width : 100 vw ; height : 100 vh " >
3+
4+ </div >
55</template >
66<script lang="ts">
77import 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 >
0 commit comments