Supabase RPC生成MVT矢量瓦片在MapLibre中无法显示的问题
排查Supabase RPC生成MVT在MapLibre中无法显示的问题
以下是从RPC函数、前端协议处理到MapLibre配置的逐项排查及修复方案:
一、Supabase RPC函数问题
1. 空瓦片场景下返回值为null
当瓦片范围内没有匹配的几何数据时,ST_AsMVT会返回空,后续的encode操作会得到null,最终函数返回null。前端处理null的base64字符串会直接报错。
修复方案:使用COALESCE确保即使没有数据也返回空的base64编码MVT,同时调整查询数据源保证始终返回一行结果:
CREATE OR REPLACE FUNCTION mvt(z integer, x integer, y integer) RETURNS text LANGUAGE plpgsql AS $$ DECLARE mvt_output text; BEGIN WITH bounds AS ( SELECT ST_TileEnvelope(z, x, y) AS geom ), mvtgeom AS ( SELECT ST_AsMVTGeom( ST_Transform(geometry, 3857), bounds.geom, 4096, 0, true ) AS geom FROM property_geodata, bounds WHERE ST_Intersects(ST_Transform(geometry, 3857), bounds.geom) ) SELECT INTO mvt_output COALESCE(encode(ST_AsMVT(mvtgeom, 'property_geodata', 4096, 'geom'),'base64'), '') FROM bounds; RETURN mvt_output; END; $$;
2. 聚合查询数据源错误
原代码中FROM mvtgeom会在无匹配数据时返回0行,导致mvt_output未赋值。改为从bounds查询(bounds始终有一行数据),确保SELECT INTO总能拿到值。
二、前端自定义协议处理问题
1. 字符串参数未转为整数
RPC函数要求z/x/y为整数类型,但正则匹配得到的是字符串,直接传递会导致类型不兼容,触发函数执行错误。
修复方案:将匹配结果转为整数:
const { data, error } = await client.rpc("mvt", { z: parseInt(result[2], 10), x: parseInt(result[3], 10), y: parseInt(result[4], 10), });
2. 空数据与错误处理缺失
当RPC返回空字符串或null时,atob会报错;错误信息未完整抛出,无法排查问题。
修复方案:添加空值判断与完整错误信息:
maplibregl.addProtocol("supabase", async (params, abortController) => { const re = new RegExp(/supabase:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/); const result = params.url.match(re); if (!result) throw new Error("Invalid tile URL format"); const { data, error } = await client.rpc("mvt", { z: parseInt(result[2], 10), x: parseInt(result[3], 10), y: parseInt(result[4], 10), }); if (error) { throw new Error(`Tile fetch error: ${error.message}`); } // 处理空数据 if (!data) { return { data: new Uint8Array() }; } const encoded = base64ToArrayBuffer(data); return { data: encoded }; });
三、MapLibre配置问题
1. 瓦片尺寸不匹配
ST_TileEnvelope默认生成256像素的瓦片,而MapLibre矢量数据源默认tileSize为512,会导致瓦片对齐错误,无法正确渲染。
修复方案:在自定义数据源中指定tileSize: 256:
"custom-tiles": { type: "vector", tiles: ["supabase://mvt/{z}/{x}/{y}"], minzoom: 2, maxzoom: 15, tileSize: 256 // 添加此行 },
2. 点击事件图层ID不匹配
点击事件中查询的polygon-layer与实际图层IDpolygon-outline不一致,导致无法捕获点击事件(虽不影响瓦片显示,但属于逻辑错误):
const features = map.queryRenderedFeatures(e.point, { layers: ["polygon-outline"], // 改为实际图层ID });
内容的提问来源于stack exchange,提问作者Nuwe Ariho
相关产品推荐
相关产品推荐

