Skip to content

Commit 0b9d472

Browse files
committedJul 6, 2024
feat:map cache
1 parent 2760bf6 commit 0b9d472

File tree

8 files changed

+75
-63
lines changed

8 files changed

+75
-63
lines changed
 

‎README.md

+21-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Just pick a country and let the music play !
88

99
(Also edit your music library to add geolocalisation link ;) )
1010

11+
Incompatible with Chrome, <audio> balise is not displayed, but the song is playing.
12+
1113
## What it is
1214

1315
- An Audio manager and player. Currently supporting MP3, OGG & WAV as I simply use <audio> html element. Sorry for all FLAC lovers.
@@ -41,6 +43,11 @@ Release :
4143

4244
## Features
4345

46+
play music and define next songs to play from
47+
- your filesystem (image)
48+
- artists view (image)
49+
- country location (image)
50+
4451
- Music library accessing in readonly mode to your local library
4552
- Musics from your fileSystem are saved in the database on the first reach.
4653
- Database persistency with metadata exposition
@@ -85,7 +92,8 @@ edit .env example before first launch :
8592

8693
## Start up
8794

88-
`docker compose up`
95+
full dockerized environment :
96+
`docker compose --profile full up`
8997

9098
- frontend (`http://localhost:3000`)
9199
- backend (`http://localhost:8000`)
@@ -99,11 +107,23 @@ edit .env example before first launch :
99107

100108
### Notes
101109

110+
config update :
111+
112+
If you want to update .env file configuration to add your email or link an other folder, don't forget to run the following command to apply changes:
113+
- `docker compose stop backend`
114+
- `docker compose up backend --build`
115+
116+
`backend` container may fail to start with error `exec /app/run_dev.sh: no such file or directory`.
117+
- run `dos2unix ./run_dev.sh` then `docker compose restart backend`
118+
102119
`backend` may fails to connect to database as it doesn't wait enough for the first db init :
103120

104121
- Wait for the db container log line `LOG: database system is ready to accept connections`. It may take a while and you may see database stopping and restarting in the process.
105122
- Then run `docker compose restart backend`.
106123

124+
`frontend` may fails to bind adress with the error `listen EADDRINUSE: address already in use`.
125+
- run `docker compose up frontend --force-recreate`
126+
107127
## dev Notes
108128

109129
front end dev, set this variable to disable API calls if you do not plan to work with the server launched

‎docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,4 @@ services:
6767
ports:
6868
- 3000:3000
6969
profiles:
70-
- front
70+
- full

‎services/frontend/src/components/InteractiveMap.vue

+40-53
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<template>
22
<v-card>
3-
<NavigatorToolbar title="Geolocalizer" :countLoaded="-1" :countRefreshCallback="refreshArtistGeoms" />
3+
<NavigatorToolbar title="Geolocalizer" :countLoaded="countLoadedData"
4+
:countRefreshCallback="refreshArtistGeoms" />
45
<v-sheet height="70vh" max-height="90vh" rounded="lg">
56
<div id="musicMap" class="mapContainer">
67
</div>
@@ -19,15 +20,28 @@ import L from 'leaflet';
1920
import "leaflet.markercluster";
2021
import type { GeomData } from '~/commons/interfaces';
2122
import { COUNTRY_FIELD_NAME, FRONT_PUBLIC_URL, PLAYLIST_TYPES } from '~/commons/constants';
22-
import { getAPI, writeErrorLogs } from '~/commons/restAPI';
23+
import { getAPI, writeErrorLogs, writeInfoLogs } from '~/commons/restAPI';
2324
import PlaylistActions from './PlaylistActions.vue';
2425
import { createGeomData } from '~/commons/utils';
2526
26-
const countriesLayerBuffers = await useAsyncData('countries', () => loadCountries());
2727
const activeCountryPopup = ref("");
28+
const countLoadedData = ref(0);
2829
const mapStore = useSpatialMapStore();
2930
const playlist = usePlaylistStore();
30-
const { editionId, editorContext, geomLayerData, countriesLayer } = storeToRefs(mapStore);
31+
const { editionId, editorContext, geomLayerData, countriesFeatures, countriesLayer } = storeToRefs(mapStore);
32+
const style = {
33+
hilight: {
34+
dashArray: '',
35+
fillColor: 'white',
36+
fillOpacity: 0.85
37+
},
38+
default: {
39+
fillOpacity: 0, weight: 1,
40+
color: 'black',
41+
}
42+
}
43+
44+
await useAsyncData('countries', () => loadCountries());
3145
const mapPlayerButton = ref();
3246
const layersCountValues = ref();
3347
const clusterPopupPlayer = ref();
@@ -60,16 +74,33 @@ watch(geomLayerData, (newVal, oldVal) => {
6074
all[value.name] = (all[value.name] ?? 0) + 1;
6175
return all;
6276
}, {});
63-
77+
countLoadedData.value = newVal.length;
6478
createReadMarkers(newVal);
6579
}
6680
})
6781
82+
watch([countriesFeatures, leafletMap], ([newValLayer, newValMap]) => {
83+
if (newValLayer && newValMap) {
84+
const cLayer = L.geoJSON(newValLayer, {
85+
style: style.default,
86+
onEachFeature: onEachFeature
87+
});
88+
cLayer.addTo(newValMap);
89+
mapStore.setCountriesLayer(cLayer);
90+
L.Icon.Default.prototype.options.className = "mapMarker";
91+
if (geomLayerData.value) {
92+
createReadMarkers(geomLayerData.value)
93+
}
94+
}
95+
},
96+
{ immediate: true });
97+
6898
async function refreshArtistGeoms() {
6999
const res = await getAPI(`/api/map/getGeometries`, 'fetch artist geoms');
70100
if (!res) {
71101
return "No data";
72102
}
103+
countLoadedData.value = res.result.length;
73104
mapStore.updateLayerData(createGeomData(res.result));
74105
return res.result.length;
75106
}
@@ -200,10 +231,6 @@ function resetCountryStyleReadMarker(a: any) {
200231
201232
onMounted(() => {
202233
initLeafletMap();
203-
L.Icon.Default.prototype.options.className = "mapMarker";
204-
if (geomLayerData.value) {
205-
createReadMarkers(geomLayerData.value)
206-
}
207234
})
208235
209236
function initLeafletMap() {
@@ -213,44 +240,16 @@ function initLeafletMap() {
213240
maxZoom: 10,
214241
attribution: '&copy; <a href="https://stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://stamen.com/" target="_blank">Stamen Design</a> &copy; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>',
215242
}).addTo(leafletMap.value);
216-
createCountriesLayer();
217243
}
218244
219245
220246
async function loadCountries() {
221-
try {
222-
return await shp(`${FRONT_PUBLIC_URL}/geodata/ne_110m_admin_0_countries`);
223-
} catch (err) {
224-
writeErrorLogs(`couldn't load shp, ${JSON.stringify(err)}`);
225-
}
226-
227-
}
228-
229-
async function createCountriesLayer() {
230-
// for some reason I can't make it work with destructuration and a watcher...
231-
if (countriesLayerBuffers.status.value === "error") {
232-
console.error(countriesLayerBuffers.error.value)
247+
if (countriesLayer.value) {
248+
writeInfoLogs("Skip countries shp loading");
233249
return
234250
}
235-
else if (countriesLayerBuffers.status.value === "pending" || countriesLayerBuffers.status.value === "idle") {
236-
console.log("countries layers loading still pending");
237-
return
238-
}
239-
const res = countriesLayerBuffers.data.value;
240-
241-
if (!res) {
242-
console.error("no result for countries layer");
243-
return
244-
}
245-
if (!leafletMap.value) {
246-
console.error("no map instanciated");
247-
return;
248-
}
249-
const cLayer = L.geoJSON(res, {
250-
style: style.default,
251-
onEachFeature: onEachFeature
252-
}).addTo(leafletMap.value);
253-
mapStore.setCountriesLayer(cLayer);
251+
const shpRes = await shp(`${FRONT_PUBLIC_URL}/geodata/ne_110m_admin_0_countries`);
252+
mapStore.setCountriesFeatures(shpRes);
254253
}
255254
256255
function onEachFeature(feature: any, layer: any) {
@@ -261,18 +260,6 @@ function onEachFeature(feature: any, layer: any) {
261260
})
262261
}
263262
264-
const style = {
265-
hilight: {
266-
dashArray: '',
267-
fillColor: 'white',
268-
fillOpacity: 0.85
269-
},
270-
default: {
271-
fillOpacity: 0, weight: 1,
272-
color: 'black',
273-
}
274-
}
275-
276263
function highlightFeature(e: any) {
277264
let layer = e.target;
278265
layer.setStyle(style.hilight);

‎services/frontend/src/components/artist/ArtistsCards.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
Server log: "{{ dataError }}"
1717
</v-alert>
1818
</v-container>
19-
<v-infinite-scroll v-else :height="300" :items="artistsData.artists" :onLoad="load">
19+
<v-infinite-scroll v-else :height="300" :onLoad="load">
2020
<v-container fluid>
2121
<v-row dense justify="start">
2222
<v-col cols="3" v-for="artist in artistsData.artists" :key="artist.id">
2323
<v-card max-width="20vw">
2424
<v-img src="/default_artist.png" gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)" cover>
25-
25+
<v-card-title class="text-white text-h6" v-text="artist.name"></v-card-title>
2626
<v-toolbar color="transparent">
27-
<v-toolbar-title class="text-white" v-text="artist.name"></v-toolbar-title>
27+
2828
<template v-slot:append>
2929
<PlaylistActions :type="PLAYLIST_TYPES.ARTIST" :value="artist.id" />
3030
</template>

‎services/frontend/src/components/artist/ArtistsGeolocalizer.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
Server log: "{{ dataError }}"
1717
</v-alert>
1818
</v-container>
19-
<v-infinite-scroll v-else height="80vh" item-height="48" :items="artistsData.artists" @load="load">
19+
<v-infinite-scroll v-else height="80vh" item-height="48" @load="load">
2020
<template v-for="(artist, index) in artistsData.artists" :key="artist.id">
2121
<v-list-item :subtitle="`${artist.country_name ?? 'NO DATA'}`" :title="`${artist.name}`">
2222
<template v-slot:prepend>

‎services/frontend/src/layouts/default.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<MusicMenu />
44
<v-main v-show="!isFocused">
55
<v-container class="background-over-milkdrop">
6-
<slot />
6+
<slot></slot>
77
</v-container>
88
</v-main>
99
<v-footer app height="50" center class="background-over-milkdrop">

‎services/frontend/src/pages/index.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</v-col>
1717
</v-row>
1818
</v-col>
19-
<v-col cols="4" class="opacity-100">
19+
<v-col cols="7" class="opacity-100">
2020
<InteractiveMap />
2121
</v-col>
2222

‎services/frontend/src/stores/spatialmap.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import L from 'leaflet';
77
export const useSpatialMapStore = defineStore('spatialMap', () => {
88
const editionId = ref<string>();
99
const editorContext = ref<ArtistMapEditorContext>();
10-
const countriesLayer = ref();
10+
const countriesLayer = ref<any>();
11+
const countriesFeatures = ref();
1112
const geomLayerData = ref<GeomData[]>()
1213

1314
function openEditionForId(id: string, context: ArtistMapEditorContext) {
@@ -44,6 +45,10 @@ export const useSpatialMapStore = defineStore('spatialMap', () => {
4445
}
4546
}
4647

48+
function setCountriesFeatures(countryFeatures: any) {
49+
countriesFeatures.value = countryFeatures;
50+
}
51+
4752
function setCountriesLayer(countryLayer: L.GeoJSON) {
4853
countriesLayer.value = countryLayer;
4954
}
@@ -61,5 +66,5 @@ export const useSpatialMapStore = defineStore('spatialMap', () => {
6166
return geom;
6267
}
6368

64-
return { editionId, editorContext, geomLayerData, countriesLayer, openEditionForId, closeEditionId, updateLayerData, getGeomFromLabel, setCountriesLayer };
69+
return { editionId, editorContext, geomLayerData, countriesLayer, countriesFeatures, openEditionForId, closeEditionId, updateLayerData, getGeomFromLabel, setCountriesLayer, setCountriesFeatures };
6570
});

0 commit comments

Comments
 (0)
Please sign in to comment.