Postgres 与 MapLibre 实时位置共享

本教程以之前对 Postgis 和 Supabase 的学习为基础,并在此基础上添加了 Supabase Realtime。如果您是此主题的新手,我们建议您先查看以下内容:

  • PostGIS 和 Supabase 入门[视频] [文档]
  • 使用 Protomaps 和 Supabase Storage 自托管地图[视频] [博客]
  • 使用 PostGIS 生成矢量切片[视频] [博客]

可以使用国内版supabase,作为supabase替代。

在本教程中,您将学习

  • 使用 Supabase Edge Function 构建一个可捕获实时位置数据的 Telegram Bot。
  • 使用 RPC(远程过程调用)将位置数据从边缘函数插入 Postgres。
  • 使用 Supabase Realtime 监听数据库的变化。
  • 在 React 中使用 MapLibre GL JS 将实时位置数据绘制到地图上。

使用 Edge Functions 将位置数据写入 Supabase

在本部分中,您将创建一个 Edge Function,用于从 Telegram Bot 捕获实时位置数据。Telegram Bot 将位置数据发送到 Edge Function,然后 Edge Function 将数据插入 Supabase。

有关如何创建 Telegram Bot 的详细指南,请参阅此处的文档。

您可以在GitHub上找到可用于生产的 Telegram Bot Supabase Edge Function 代码。这是监听实时位置更新并将其写入数据库的相关代码:

/supabase/functions/telegram-bot/index.ts​

import { Bot, webhookCallback } from 'https://deno.land/x/grammy@v1.20.3/mod.ts'
import { createClient } from 'jsr:@supabase/supabase-js@2.39.7'
import { Database } from '../_shared/database.types.ts'

const token = Deno.env.get('BOT_TOKEN')
if (!token) throw new Error('BOT_TOKEN is unset')

const supabase = createClient<Database>(
  Deno.env.get('SUPABASE_URL')!,
  Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)

const bot = new Bot(token)
// ...

bot.on('edit:location', async (ctx) => {
  const {
    location,
    from: { id: user_id },
    edit_date,
  } = ctx.update.edited_message!
  if (location) {
    // Insert into db
    const { error } = await supabase.rpc('location_insert', {
      _user_id: user_id,
      _lat: location.latitude,
      _long: location.longitude,
      _timestamp: edit_date,
    })
    if (
      error &&
      error.message !==
        'null value in column "event_id" of relation "locations" violates not-null constraint' &&
      error.message !== 'duplicate key value violates unique constraint "locations_pkey"'
    ) {
      return console.log(`edit:location:insert:error:user:${user_id}: ${error.message}`)
    }
  }
  return
})

const handleUpdate = webhookCallback(bot, 'std/http')

Deno.serve(async (req) => {
  const headers = req.headers
  try {
    const url = new URL(req.url)
    if (url.searchParams.get('secret') !== Deno.env.get('FUNCTION_SECRET')) {
      return new Response('not allowed', { status: 405 })
    }

    return await handleUpdate(req)
  } catch (err) {
    console.log(headers)
    console.error(err)
  }
  return new Response()
})

使用 RPC 将位置数据插入Postgres

上面的边缘函数使用 RPC(远程过程调用)将位置数据插入数据库。RPC 在我们的Supabase Migrations中定义。RPC 首先验证用户是否有活动会话,然后将位置数据插入表中locations

CREATE OR REPLACE FUNCTION public.location_insert(_timestamp bigint, _lat double precision, _long double precision, _user_id bigint)
RETURNS void AS $$
declare active_event_id uuid;
begin
  select event_id into active_event_id from public.sessions where user_id = _user_id and status = 'ACTIVE'::session_status;

  INSERT INTO public.locations(event_id, user_id, created_at, lat, long, location)
  VALUES (active_event_id, _user_id, to_timestamp(_timestamp), _lat, _long, st_point(_long, _lat));
end;
$$ LANGUAGE plpgsql VOLATILE;

使用 Supabase Realtime 监听数据库的变化

在本节中,您将使用 Supabase Realtime 监听数据库中的更改。Realtime API 是一个功能强大的工具,可让您将数据库中的更改广播到多个客户端。

用于监听实时变化并在地图上绘制标记的完整客户端代码可在GitHub上找到。

我们将把它分为几个步骤:

由于我们在 React 中工作,我们将在钩子中设置实时订阅useEffect。如果您使用的是 Next.js,则必须标记这一点,use client因为我们需要客户端 JavaScript 来实现这一点:

/app/app/realtimemap/%5Bevent%5D/page.tsx

// ...
export default function Page({ params }: { params: { event: string } }) {
  const supabase = createClient<Database>()
  const [locations, setLocations] = useState<{
    [key: string]: Tables<'locations'>
  } | null>(null)
  const locationsRef = useRef<{
    [key: string]: Tables<'locations'>
  } | null>()
  locationsRef.current = locations

  useEffect(() => {
    // Listen to realtime updates
    const subs = supabase
      .channel('schema-db-changes')
      .on(
        'postgres_changes',
        {
          event: 'INSERT', // Listen only to INSERTs
          schema: 'public',
          table: 'locations',
          filter: `event_id=eq.${params.event}`,
        },
        (payload) => {
          const loc = payload.new as Tables<'locations'>
          const updated = {
            ...locationsRef.current,
            [loc.user_id.toString()]: loc,
          }

          setLocations(updated)
        }
      )
      .subscribe()
    console.log('Subscribed')

    return () => {
      subs.unsubscribe()
    }
  }, [])
// ...

在 React 中使用 MapLibre GL JS 将实时位置数据绘制到地图上

locations上面的实时订阅监听器会在对象插入到表中时使用新的位置数据更新对象的状态。现在我们可以react-map-gl轻松地将位置标记绘制到地图上:

/app/app/realtimemap/%5Bevent%5D/page.tsx

// ...
<Map
  className="map"
  cooperativeGestures={true}
  initialViewState={{
    longitude: 103.852713,
    latitude: 1.285727,
    zoom: 13,
  }}
  mapStyle={{
    version: 8,
    glyphs: 'https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf',
    sources: {
      protomaps: {
        attribution:
          '<a href="https://github.com/protomaps/basemaps">Protomaps</a> © <a href="https://openstreetmap.org">OpenStreetMap</a>',
        type: 'vector',
        url: 'pmtiles://https://<project_ref>.supabase.co/functions/v1/maps-private/my_area.pmtiles',
      },
    },
    transition: {
      duration: 0,
    },
    // @ts-ignore
    layers: layers('protomaps', 'light'),
  }}
  // @ts-ignore
  mapLib={maplibregl}
>
  {Object.entries(locations).map(([key, value]) => (
    <Marker key={key} longitude={value.long} latitude={value.lat} color="red" />
  ))}
</Map>

请注意,我们在此使用托管在 Supabase Storage 上的Protomaps作为基础地图。要了解此内容,请阅读我们之前的教程。

就是这样,使用 Supabase 向您的应用程序添加实时位置数据就是这么简单!我们迫不及待地想看看您将构建什么!

结论

Supabase Realtime 非常适合向多个客户端广播位置数据。结合 PostGIS 的强大功能和更广泛的 Postgres 扩展生态系统,它是满足您所有地理空间需求的强大解决方案!

想要了解有关地图和 PostGIS 的更多信息?请务必关注我们的Twitter和YouTube频道,以免错过!到时候见!

更多 Supabase #

  • 观看视频指南
  • 国内版supabase
  • 查找代码
  • 构建您自己的开源 Google Maps API 替代方案
  • 使用 Protomaps 在 Supabase 存储上自托管地图
  • PostGIS 入门
  • PostGIS 文档指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/784807.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.Python4:requests

1.requests爬虫原理 &#xff08;1&#xff09;requests是一个python的第三方库&#xff0c;主要用于发送http请求 2.正则表达式 #正则表达式 import re,requests str1aceace #A(.*?)B,匹配A和B之间的值 print(re.findall(a(.*?)e,str1))import re,requests str2hello com…

Redis-Jedis连接池\RedisTemplate\StringRedisTemplate

Redis-Jedis连接池\RedisTemplate\StringRedisTemplate 1. Jedis连接池1.1 通过工具类1.1.1 连接池&#xff1a;JedisConnectionFactory&#xff1a;1.1.2 test&#xff1a;&#xff08;代码其实只有连接池那里改变了&#xff09; 2. SpringDataRedis&#xff08;lettuce&#…

滑动窗口(同向的双指针)

通过 双指针的 同向移动 算法应用的场景&#xff1a; 满足xxx条件&#xff08;计算结果&#xff0c;出现次数&#xff0c;同时包含&#xff09; 最长/最短 子串 /子数组/子序列 例如&#xff1a;长度最小的子数组 滑动窗口 使用思路 &#xff08;寻找最长&#xff09; –核心…

刷题(day01)

1、leetcode485.最大连续1的个数 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,0,1,1,1] 输出&#xff1a;3 解释&#xff1a;开头的两位和最后的三位都是连续 1 &#xff0c;所以最大连续 1 的个数是 3.…

基于CentOS Stream 9平台搭建FRP内网穿透

内网穿透方法很多&#xff0c;本文以github上很火的frp为例 1.frp官方 文档&#xff1a;https://gofrp.org/zh-cn/docs/overview/ 1.1 下载 https://github.com/fatedier/frp/releases 选中合适的版本 2. 服务端&#xff08;服务器&#xff09;搭建frps 需要公网IP服务器 选…

假期笔记1:anaconda的安装与pycharm中的引用

1.下载安装 Download Anaconda Distribution | Anaconda 2.填个邮箱 11111.. 3.下载。有点需要时间 4.安装&#xff0c;双击&#xff0c;根据实际进行&#xff0c;记清安装路径 5。环境设置 conda -V 6.创建环境 conda create --name env_name conda create --na…

Qt文档阅读笔记-Queued Custom Type Example

此篇展示了使用Qt编写多线程程序。 概述 此案例创建一Block类&#xff0c;用于存储数据&#xff0c;并且在元对象系统中注册后&#xff0c;在多线程中进行信号与槽函数的连接中充当参数。 Block类 在元对象系统中&#xff0c;注册类&#xff0c;需要类在public部分提供默认构…

基于SSM的志愿者服务平台

基于SSM的志愿者服务平台系统主要其系统包括不同的端组成&#xff0c;前端主要包括系统用户管理、新闻数据管理、变幻图管理、志愿者管理、培训视频管理、志愿者项目管理、服务时长管理、交流分享管理、志愿者表彰管理。前台主要包括网站首页、培训视频、志愿者项目、交流分享、…

React+TS前台项目实战(二十六)-- 高性能可配置Echarts图表组件封装

文章目录 前言CommonChart组件1. 功能分析2. 代码详细注释3. 使用到的全局hook代码4. 使用方式5. 效果展示 总结 前言 Echarts图表在项目中经常用到&#xff0c;然而&#xff0c;重复编写初始化&#xff0c;更新&#xff0c;以及清除实例等动作对于开发人员来说是一种浪费时间…

C语言相关内容模块

C语言相关内容模块 1、函数指针定义方式 1、函数指针定义方式 函数指针的具体用法

最近点对问题(算法与数据结构设计)

课题内容和要求 最近点对问题&#xff0c;在二维平面上输入n个点列P。其中任一点pi&#xff08;xi&#xff0c;yi&#xff09;&#xff0c;编写程序求出最近的两个点。使用穷举法实现&#xff0c;算法复杂度O(n2)&#xff1b;优化算法&#xff0c;以O(nlog2n)实现这一问题 数…

阶段三:项目开发---民航功能模块实现:任务24:航空实时监控

任务描述 内 容&#xff1a;地图展示、飞机飞行轨迹、扇区控制。航空实时监控&#xff0c;是飞机每秒发送坐标&#xff0c;经过终端转换实时发送给塔台&#xff0c;为了飞机位置的精准度&#xff0c;传输位置的密度很大&#xff0c;在地图位置显示不明显。本次为了案例展示效…

AI系统的PyTorch:TextGrad框架基于文本梯度实现大语言模型AI系统自优化!

AI系统的PyTorch&#xff1a;TextGrad框架基于文本梯度实现大语言模型AI系统自优化&#xff01; 原创 旺知识 旺知识 2024年07月07日 16:21 广东 人工智能&#xff08;AI&#xff09;正在经历一场范式转变&#xff0c;这一转变是由系统协调多个大型语言模型&#xff08;LLMs&…

51 单片机[7]:计时器

一、定时器 1. 定时器介绍 51单片机的定时器属于单片机的内部资源&#xff0c;其电路的连接和运转均在单片机内部完成。 定时器作用&#xff1a; &#xff08;1&#xff09;用于计时系统&#xff0c;可实现软件计时&#xff0c;或者使程序每隔一固定时间完成一项操作 &#…

【零基础】学JS之APIS(基于黑马)

喝下这碗鸡汤 披盔戴甲,一路勇往直前! 1. 什么是事件 事件是在编程时系统内发生的动作或者发生的事情 比如用户在网页上单击一个按钮 2. 什么是事件监听? 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应&#xff0c;也称为 注…

【人工智能】—基于成都市各区(市)县租房价格预测建模研究

引言 随着城市化进程的加速&#xff0c;人口流动日益频繁&#xff0c;租房市场作为城市生活的重要组成部分&#xff0c;其价格波动对居民生活质量和城市经济发展具有显著影响。成都市&#xff0c;作为中国西部地区的经济、文化、交通和科技中心&#xff0c;近年来吸引了大量人…

5.Python学习:面向对象

1.面向对象和面向过程的区别 以下五子棋为例&#xff1a; 2.类和实例 &#xff08;1&#xff09;类是抽象的模板&#xff0c;实例是根据模板创建出来的具体的对象 &#xff08;2&#xff09;比如人类就是一个类&#xff0c;刘亦菲就是人类的一个实例 2.1 新建类和类的实例…

王老师 linux c++ 通信架构 笔记(三)安装 xftp、

&#xff08;11&#xff09;调整 xshell 终端的字体大小&#xff0c;默认字体大小是 9 &#xff1a; &#xff08;12&#xff09; 共享文件夹 hgfs 的含义&#xff1a; &#xff08;13&#xff09;安装 xftp &#xff0c; 傻瓜式安装&#xff0c;出了修改下默认安装位置。 操作…

上位机图像处理和嵌入式模块部署(mcu项目2:串口日志记录器)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 淘宝上面有一个商品蛮好玩的&#xff0c;那就是日志记录器。说是记录器&#xff0c;其实就是一个模块&#xff0c;这个模块的输入是一个ttl串口&am…

18.动态规划之斐波那契数列模型1

1.第N个斐波那契数 1137. 第 N 个泰波那契数 - 力扣&#xff08;LeetCode&#xff09; 做题流程 1. 状态表示&#xff1a; 这道题可以【根据题目的要求】直接定义出状态表示&#xff1a; dp[i] 表示&#xff1a;第 i 个泰波那契数的值。 2. 状态转移方程&#xff1a; …