大名网站建设价格,建设局招标网站,湖南建筑一体化平台,电子商务网站建设的模式您喜欢视听学习吗#xff1f;观看视频指南#xff01;
或者直接跳到代码
Overture Maps Foundation是由亚马逊、Meta、微软和 tomtom 发起的联合开发基金会项目#xff0c;旨在创建可靠、易于使用、可互操作的开放地图数据。
Overture Maps 允许我们以GeoJSON格式下载开放…
您喜欢视听学习吗观看视频指南
或者直接跳到代码
Overture Maps Foundation是由亚马逊、Meta、微软和 tomtom 发起的联合开发基金会项目旨在创建可靠、易于使用、可互操作的开放地图数据。
Overture Maps 允许我们以GeoJSON格式下载开放地图数据例如名胜古迹我们可以将其转换为 SQL 并导入 Supabase 上的 Postgres 数据库。
使用 PostGIS我们可以以编程方式生成矢量图块并使用 supabase-js 将它们提供给我们的 MapLibre GL 客户端。
矢量图块是地理数据包被打包成预定义的大致正方形的“图块”以便在网络上传输。客户端请求的地图数据是一组“图块”对应于预定义大小和位置的方形土地区域。
特别是对于大型数据集这样做的好处是数据传输大大减少因为只需要传输当前视口内和当前缩放级别的数据。
在本教程中您将学习
使用 Overture Maps 以 GeoJSON 格式下载开放地图地点数据。使用 GDAL ogr2ogr 将 GeoJSON 转换为 SQL 语句。使用 psql 将位置数据和 JSON 元数据导入您的 Supabase Postgres 数据库。使用 PostGISST_AsMVT将与图块层对应的一组行聚合为二进制矢量图块表示。addProtocol通过使用 supabase-js 进行远程过程调用使用 MapLibre可视化大型 PostGIS 表。使用 supabase-js 按需获取其他 JSON 元数据
使用 Overture Maps 下载开放地图数据
Overture Maps 提供了一个Python 命令行工具来下载感兴趣区域内的数据并将其转换为几种常见的地理空间文件格式。
我们可以使用以下命令将新加坡的地点下载到 GeoJSON 文件中
overturemaps download --bbox103.570233,1.125077,104.115855,1.490957 -f geojson --typeplace -o places.geojson
根据边界框的大小这可能需要相当长的时间
将 GeoJSON 转换为SQL
下一步我们可以使用GDAL ogr2ogr将 GeoJSON 文件转换为 PostGIS 兼容的 SQL 文件。
您可以GDAL通过安装homebrew brew install gdal或按照下载说明进行操作。
PG_USE_COPYtrue ogr2ogr -f pgdump places.sql places.geojson
将位置数据导入 Supabase
在专用的单独架构上启用 Supabase 数据库上的 PostGIS 扩展gis。为此您可以导航到SQL 编辑器并运行以下 SQL或者您可以从数据库扩展设置中启用扩展。也可使用国内版supabase
由于 PostGIS 的计算量可能很大我们建议在专用的单独模式上启用它例如名为gis
CREATE SCHEMA IF NOT EXISTS gis;
CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA gis;
将打开的地图数据导入到placesSupabase中的表中
psql -h aws-0-us-west-1.pooler.supabase.com -p 5432 -d postgres -U postgres.project-ref places.sql
您可以在Supabase 仪表板的数据库设置中找到凭据。
启用 RLS 并创建公共读取策略
我们希望地点数据可以公开获取因此我们可以创建一个允许公开读取的行级安全策略。
在您的 Supabase 仪表板中导航到SQL 编辑器并运行以下命令
ALTER TABLE public.places ENABLE ROW LEVEL SECURITY;CREATE POLICY Enable read access for all users ON public.places FOR SELECT USING (true);
使用PostGIS生成矢量图块
为了在客户端请求时以编程方式生成矢量图块我们需要创建一个 Postgres 函数可以通过远程过程调用来调用它。在 SQL 编辑器中运行
CREATE OR REPLACE FUNCTION mvt(z integer, x integer, y integer)
RETURNS text
LANGUAGE plpgsql
AS $$
DECLAREmvt_output text;
BEGINWITH-- Define the bounds of the tile using the provided Z, X, Y coordinatesbounds AS (SELECT ST_TileEnvelope(z, x, y) AS geom),-- Transform the geometries from EPSG:4326 to EPSG:3857 and clip them to the tile boundsmvtgeom AS (SELECT-- include the name and id only at zoom 13 to make low-zoom tiles smallerCASEWHEN z 13 THEN idELSE NULLEND AS id,CASEWHEN z 13 THEN names::json-primaryELSE NULLEND AS primary_name,categories::json-main as main_category,ST_AsMVTGeom(ST_Transform(wkb_geometry, 3857), -- Transform the geometry to Web Mercatorbounds.geom,4096, -- The extent of the tile in pixels (commonly 256 or 4096)0, -- Buffer around the tile in pixelstrue -- Clip geometries to the tile extent) AS geomFROMplaces, boundsWHEREST_Intersects(ST_Transform(wkb_geometry, 3857), bounds.geom))-- Generate the MVT from the clipped geometriesSELECT INTO mvt_output encode(ST_AsMVT(mvtgeom, places, 4096, geom),base64)FROM mvtgeom;RETURN mvt_output;
END;
$$;
为了限制通过网络发送的数据量我们限制了矢量图块中包含的元数据量。例如我们为缩放级别添加了一个条件并且只有当用户放大到 13 级以上时才返回地名。
使用 supabase-js 从 MapLibre GL 客户端获取矢量瓦片
index.html您可以在GitHub上找到完整的代码。在这里我们将重点介绍如何向 MapLibreGL 添加新协议以通过 supabase-js 获取 bas64 编码的二进制矢量瓦片数据以便 MapLibre GL 可以在用户与地图交互时获取和呈现数据
index.html
const client supabase.createClient(your-supabase-api-url, your-supabase-anon-key)function base64ToArrayBuffer(base64) {var binaryString atob(base64)var bytes new Uint8Array(binaryString.length)for (var i 0; i binaryString.length; i) {bytes[i] binaryString.charCodeAt(i)}return bytes
}maplibregl.addProtocol(supabase, async (params, abortController) {const re new RegExp(/supabase:\/\/(.)\/(\d)\/(\d)\/(\d)/)const result params.url.match(re)const { data, error } await client.rpc(mvt, {z: result[2],x: result[3],y: result[4],})const encoded base64ToArrayBuffer(data)if (!error) {return { data: encoded }} else {throw new Error(Tile fetch error:)}
})注册 supabase 协议后我们现在可以将其添加到 MapLibre GL 源中并放置在底图如Protomaps之上例如
index.html
// ...
const map new maplibregl.Map({hash: true,container: map,style: {version: 8,glyphs: https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf,sources: {supabase: {type: vector,tiles: [supabase://boston/{z}/{x}/{y}],attribution: © a hrefhttps://overturemaps.orgOverture Maps Foundation/a,},protomaps: {type: vector,url: https://api.protomaps.com/tiles/v3.json?keyyour-protomaps-api-key,attribution: Basemap © a hrefhttps://openstreetmap.orgOpenStreetMap/a,},},},
})
// ...按需获取额外的 JSON 元数据
为了限制通过网络发送的数据量我们不会对矢量图块本身中的所有元数据进行编码而是设置一个 onclick 处理程序以在 MapLibre GL 弹出窗口中按需获取其他元数据
index.html
// ..
const popup new maplibregl.Popup({closeButton: true,closeOnClick: false,maxWidth: none,
})function loadDetails(element, id) {element.innerHTML loading...client.from(places).select(websites,socials,phones,addresses,source: sources-0-dataset).eq(id, id).single().then(({ data, error }) {if (error) return console.error(error)element.parentElement.innerHTML pre${JSON.stringify(data, null, 2)}/pre})
}map.on(click, overture-pois-text, async (e) {if (e.features.length 0) {const feature e.features[0]console.log(feature)popup.setHTML(table stylefont-size:12pxtrtdid:/tdtd${feature.properties.id}/td/trtrtdname:/tdtd${feature.properties.primary_name}/td/trtrtdmain_category:/tdtd${feature.properties.main_category}/td/trtrtddetails:/tdtdspan οnclickloadDetails(this, ${feature.properties.id})load details/span/td/tr/table)popup.setLngLat(e.lngLat)popup.addTo(map)}
})
// ...结论
PostGIS 功能强大可让您以编程方式从存储在 Postgres 中的表行生成矢量图块。与 Supabase 自动生成的 REST API 和 supabase-js 客户端库配合使用您可以轻松构建交互式地理空间应用程序
更多 Supabase
观看视频指南国内版suapbase查找代码使用 Protomaps 在 Supabase 存储上自托管地图PostGIS 入门PostGIS 文档指南
原文章https://supabase.com/blog/postgis-generate-vector-tiles