Skip to Content

Realtime Map Application (Vue) using Geobase

geobase-realtime-vue

This document describes the implementation of a realtime map application that allows users to broadcast their position, drop pins, and view other users in real time.

Key Features

  1. Presence Tracking

    • Users join a shared room and their online presence is tracked.
    • Displays the total number of online users and their generated usernames.
  2. Realtime Movement

    • Users can move their cursor on the map, and their position is broadcasted to others.
    • Other users’ movements are displayed on the map with color-coded markers.
  3. Pin Dropping

    • Users can drop pins at specific locations on the map.
    • Pins are stored in the pins table in Geobase and broadcasted in real time to all users.
  4. Session Management

    • User sessions are tracked to manage online users.

Ensure that your Geobase configuration is correctly set up to handle real-time data efficiently.


Component: MapScreen.vue

Template

The UI includes a full-screen map with information panels for the user ID, online users, and status.

<template> <div class="h-screen w-screen relative"> <div ref="mapContainerRef" class="h-full w-full"></div> <div class="info-panel"> <div class="info-item"> <strong>Your ID:</strong> {{ userId }} </div> <div class="info-item"> <strong>Online Users:</strong> {{ Object.keys(presenceState).length }} </div> <div class="info-item"> <strong>Status:</strong> {{ status }} </div> </div> <div class="online-users"> <h3>Online Users</h3> <ul> <li v-for="(name, uid) in presenceState" :key="uid" class="user-item"> <img :src="getUserAvatar(uid)" alt="avatar" class="user-avatar" /> <span>{{ name }}</span> </li> </ul> </div> </div> </template>

Script Logic

  1. Map Initialization

    • Uses MapLibre to render the map.
    • Tracks mouse movement and pin drop events.
  2. Geobase Realtime Setup

    • Initializes a Geobase channel for presence and broadcast events.
    • Listens for mouse-move and pin-drop events to update the map in real time.
  3. Presence Management

    • Tracks users joining or leaving the room and updates the presenceState.
  4. Pin Management

    • Loads existing pins from the pins table on mount.
    • Saves new pins to the Geobase database.

The map and presence features are designed to provide a seamless real-time experience for users.

<script> import { ref, reactive, onMounted, onUnmounted } from "vue"; import { v4 as uuidv4 } from "uuid"; import maplibregl from "maplibre-gl"; import "maplibre-gl/dist/maplibre-gl.css"; import { throttle } from "lodash"; import { Geobase } from "../../lib/geobase"; import { getUserAvatar } from "../../lib/avatars"; export default { setup() { const userId = ref(uuidv4()); const presenceState = reactive({}); const status = ref("Idle"); const mapRef = ref(null); const mapContainerRef = ref(null); const markersRef = reactive({}); const pinsRef = ref([]); const channelRef = ref(null); // Map Initialization onMounted(() => { mapRef.value = new maplibregl.Map({ container: mapContainerRef.value, style: "https://demotiles.maplibre.org/style.json", center: [0, 0], zoom: 2, }); initializePresenceChannel(); loadPins(); }); // Pin Dropping const dropPin = async (lngLat) => { const marker = new maplibregl.Marker() .setLngLat(lngLat) .addTo(mapRef.value); pinsRef.value.push(marker); await Geobase.from("pins").insert([{ user_id: userId.value, x: lngLat.lng, y: lngLat.lat }]); }; // Presence Initialization const initializePresenceChannel = () => { channelRef.value = Geobase.channel("room_01", { presence: { key: userId.value } }); channelRef.value.subscribe(); }; return { mapContainerRef, userId, presenceState, status }; }, }; </script>

Styling

The map and information panels are styled with utility classes:

.h-screen { height: 100vh; } .w-screen { width: 100vw; } .info-panel { position: absolute; top: 10px; left: 10px; background: rgba(255, 255, 255, 0.9); padding: 10px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } .online-users { position: absolute; top: 10px; right: 10px; background: rgba(255, 255, 255, 0.9); padding: 10px; border-radius: 8px; }

Geobase Configuration

Ensure the following table is set up in Geobase:

CREATE TABLE pins ( user_id UUID NOT NULL, x FLOAT NOT NULL, y FLOAT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, geom GEOMETRY );

Table: pins

ColumnTypeDescription
user_idUUIDUser’s unique identifier
xFLOATLongitude of the pin
yFLOATLatitude of the pin
created_atTIMESTAMPTimestamp of pin creation
geomGEOMETRYGeometric data of the pin

Any issues with the Geobase setup can lead to data inconsistencies or application errors.


Environment Variables

To connect your app to Geobase, configure these environment variables. Include them in a .env.local file for local development.

VITE_GEOBASE_URL=<Your Geobase URL> VITE_GEOBASE_ANON_KEY=<Your Geobase Anon Key>

You can locate the project reference and anon key in your Geobase project settings.

Shareable Maps

Local Development

  • Set Node.js version: Use Node version 21:
    nvm use 21
  • Install dependencies: Use your preferred package manager:
    npm install # or yarn # or pnpm install
  • Start the development server with HTTPS enabled:
    npm run dev --experimental-https # or yarn dev --experimental-https # or pnpm dev --experimental-https
ℹ️

Note: Without --experimental-https, the email verification links might redirect to https://localhost:5173/..., causing errors. You can navigate manually by removing https from the URL if needed.

Access the project at http://localhost:5173.

Database Overview

The database structure supports real-time collaboration with these key tables:

  • public.pins: Stores map pin locations

Database Table

Learn More

For additional information, refer to:

ℹ️

For support, join our Discord community .


Source: GitHub - decision-labs/geobase-vue-realtime 

Last updated on