query-features
本文回答:完整的 CAD 实体类型
name='xx'列表、后台数据库表结构、所有 SQL 字段含义对照、各类查询接口(条件 / 点 / 矩形 / 多边形 / 分页)的用法、查询结果的字段与绘制姿势。本文是后台数据查询的"主参考"。简化速查见 query-sql;表达式查询(内存模式)见 query-expression;综合用例见 query-cases;全文搜索见 query-fulltext;服务端高亮 / 过滤见 svr-style-var。
一、查询的前置条件
-
几何渲染方式打开(GeomRender):后台走几何渲染查询命令。能用
rectQueryFeature/pointQueryFeature(空间查询)。await svc.openMap({ mapid, mapopenway: vjmap.MapOpenWay.GeomRender });✅ 公共云 sys_zp、GeomRender 下:
conditionQueryFeature在 GeomRender 下可用——condition:"objectid>0"+limit:3返回 3 条(recordCount=6992),空条件返回全部。字段条件、limit、beginpos 分页都生效。注意区分:
conditionQueryFeature(SQL 条件)是几何渲染专属——内存模式进程收到querytype:"condition"直接返回{error:"not support query type!"};exprQueryFeature(表达式查询)在 GeomRender / Memory 下都可用(GeomRender 下能跑但不走空间库,较慢)。 -
内存模式打开(Memory):只能用 query-expression 的
exprQueryFeature与pointQueryFeature/rectQueryFeature(点查询恒返回 1 条,几何只给外包矩形),不能用conditionQueryFeature。 -
limit/beginpos分页:GeomRender 生效——rect 全图 +limit:3返回 3 条(不传 limit 默认上限 100),condition +limit/beginpos正常翻页。0 命中时没有result键:条件查询返回{recordCount:0},点/矩形查询返回{}——统一res.result ?? []兜底。 -
任何查询 SDK 调用都返回
{ error?, recordCount, result: [...] },业务上必须先判error。
二、后台数据库表结构
把图以"几何渲染"方式打开后,每个实体在后台都是一行记录。SQL 条件只写 where 之后的部分(不要写 select * from xxx where)。
| 字段名 | 类型 | 说明 |
|---|---|---|
id |
integer | 自增 ID |
objectid |
text | 实体唯一 ID(图重新加载后稳定)。命名规则见下文 |
layerindex |
integer | 图层索引 |
name |
text | 实体类型值(字符串,如 '1' = AcDbLine)。所有取值见第三节 |
color |
int | 颜色(RGB+Alpha 编码,常见为负数,见第二节末) |
data |
blob | 几何数据(二进制,前端不直接用) |
s1 |
text | 线型 |
s2 |
text | 扩展字典数据 |
s3 |
text | 字符型属性 3(含义随实体类型变,见第四节) |
s4 |
text | 字符型属性 4(含义随实体类型变) |
s5 |
text | 字符型属性 5(含义随实体类型变) |
n1 |
float | 颜色索引 |
n2 |
float | 线型比例 |
n3 |
float | 线宽 |
n4 |
float | 透明度 |
n5 |
float | 数值型属性 5(含义随实体类型变) |
n6 |
float | 数值型属性 6(含义随实体类型变) |
n7 |
float | 数值型属性 7(含义随实体类型变) |
n8 |
float | 数值型属性 8(含义随实体类型变) |
n9 |
float | 数值型属性 9(含义随实体类型变) |
n10 |
float | 数值型属性 10(含义随实体类型变) |
geom |
GEOMETRY | 实体外包矩形(用于空间查询,墨卡托坐标) |
objectid 命名规则(重要)
- 普通实体:
{实体句柄},如1A;同一实体拆成多行时追加_{序号}(如9EA9_0、1A_1…) - 块内实体:
{块参照id链}_{实体id}_{标记},如9BE_5C_3F_#。id 链按"最外层块参照 → 直接所属块"排列;尾部标记区分来源:_= 一般组合实体、_@= 表格内、_#= 块参照内(无标注块)、_$= 标注或含标注块的块内 - 组(group):
{实体id}${组id},如5C$2A(实体在前,组在后) - 表格(table):
{块参照id链}_{实体id}_@,如1A_5C_@
用
objectid like 'EA_%'可查到最外层块参照 id 为EA的所有子实体。
color 编码
- 颜色由 RGB + Alpha 组合:
color = 0xAABBGGRR(低字节是 R) - 例:黑色不透明 =
0xFF000000,按有符号 32 位读取就是-16777216 - 例:红色不透明 =
0xFF0000FF(红在低位),即-16776961 - 实际查询时用整数:
name='13' and color=-16776961(红色单行文字)
前端拿到后转 HTML 颜色:
vjmap.entColorToHtmlColor(color)。
三、所有实体类型 name='xx' 完整列表
⚠️
name是字符串,SQL 里要写name='1'而不是name=1。
name |
类名 | 中文 | 备注 |
|---|---|---|---|
'1' |
AcDbLine | 直线 | |
'2' |
AcDbPolyline | 多段线(LWPolyline) | |
'3' |
AcDb2dPolyline | 二维折线 | |
'4' |
AcDb3dPolyline | 三维多段线 | |
'5' |
AcDbSpline | 样条曲线 | |
'6' |
AcDbArc | 圆弧 | |
'7' |
AcDbCircle | 圆 | |
'8' |
AcDbEllipse | 椭圆 | |
'9' |
AcDbCurve | 曲线 | |
'10' |
AcDbBlockReference | 块参照 | 子实体的 objectid 以块 ID 开头 |
'11' |
AcDbHatch | 填充 | |
'12' |
AcDbMText | 多行文本 | |
'13' |
AcDbText | 单行文本 | |
'14' |
AcDbShape | 型实体 | |
'15' |
AcDbRasterImage | 栅格图片 | |
'16' |
AcDbWipeout | 遮罩实体 | |
'17' |
AcDb2LineAngularDimension | 角度标注(两条线) | |
'18' |
AcDb3PointAngularDimension | 角度标注(三点) | |
'19' |
AcDbAlignedDimension | 对齐标注 | |
'20' |
AcDbArcDimension | 圆弧标注 | |
'21' |
AcDbDiametricDimension | 直径标注 | |
'22' |
AcDbOrdinateDimension | 坐标标注 | |
'23' |
AcDbRadialDimension | 半径标注 | |
'24' |
AcDbRadialDimensionLarge | 半径折线标注 | |
'25' |
AcDbRotatedDimension | 转角标注 | |
'26' |
AcDbAttributeDefinition | 属性注记 | 文本类 |
'27' |
AcDbAttribute | 块属性 | 文本类,块内 |
'28' |
AcDbTable | 表格 | |
'29' |
AcDbMLeader | 引线标注 | |
'30' |
AcDbRegion | 面域 | |
'31' |
AcDbPolyFaceMesh | 多面网格实体 | |
'32' |
AcDbPolygonMesh | 多边形网格 | |
'33' |
AcDbSurface | 曲面 | |
'34' |
AcDb3dSolid | 三维实体 | |
'35' |
AcDbFace | 三维面 | |
'36' |
AcDbSolid | 实线实体 |
常用分组(写 SQL 时常合并查询)
-- 所有"线段"类(直线、二三维多段线)
name='1' or name='2' or name='3' or name='4'
-- 所有"曲线"类(圆弧、圆、椭圆、样条、曲线)
name='5' or name='6' or name='7' or name='8' or name='9'
-- 所有"文字"类(单行 / 多行 / 属性注记 / 块属性)
name='12' or name='13' or name='26' or name='27'
-- 所有"标注"类
name='17' or name='18' or name='19' or name='20' or name='21'
or name='22' or name='23' or name='24' or name='25' or name='29'
-- 所有"网格 / 面 / 体"类
name='30' or name='31' or name='32' or name='33' or name='34' or name='35'
不要硬编码 ID(推荐做法)
后台返回的 name ID 在不同版本可能调整。生产代码里用映射表:
const { entTypeIdMap } = await svc.getConstData();
// entTypeIdMap 形如 { '1': 'AcDbLine', '2': 'AcDbPolyline', ... }
const getTypeIdByName = name =>
Object.keys(entTypeIdMap).find(k => entTypeIdMap[k] === name);
const lineId = getTypeIdByName('AcDbLine');
const cond = `name='${lineId}'`;
四、字段含义随类型变化(s3/s4/s5/n5~n10)
下表显示各实体类型对应字段的实际含义。空白处表示该类型不使用该字段。
| 类型 | 类名 | 中文 | s3 | s4 | s5 | n5 | n6 | n7 | n8 | n9 | n10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
'1' |
AcDbLine | 直线 | points | thickness | length | ||||||
'2' |
AcDbPolyline | 多段线 | points | bulge | data3d | area | isclosed | lineTypeScale | thickness | elevation | |
'3' |
AcDb2dPolyline | 二维折线 | points | area | isclosed | polyType | thickness | elevation | |||
'4' |
AcDb3dPolyline | 三维多段线 | points | area | isclosed | polyType | |||||
'5' |
AcDbSpline | 样条曲线 | points | area | isclosed | isFit | fitTol | degree | |||
'6' |
AcDbArc | 圆弧 | center | points | area | isclosed | radius | startAngle | endAngle | thickness | |
'7' |
AcDbCircle | 圆 | center | area | isclosed | radius | thickness | ||||
'8' |
AcDbEllipse | 椭圆 | center | majorAxis | points | area | isclosed | radiusRatio | startAngle | endAngle | majorRadius |
'9' |
AcDbCurve | 曲线 | area | isclosed | |||||||
'10' |
AcDbBlockReference | 块参照 | positon | attributeDef | blockname | rotate | scaleX | scaleY | scaleZ | ||
'11' |
AcDbHatch | 填充 | points | patternName | elevation | patternAngle | patternScale | ||||
'12' |
AcDbMText | 多行文本 | location | contents | text | height | width | rotate | textHeight | actualHeight | actualWidth |
'13' |
AcDbText | 单行文本 | location | text | textStyle | height | rotate | horzMode | |||
'14' |
AcDbShape | 型实体 | positon | normal | rotate | size | |||||
'15' |
AcDbRasterImage | 栅格图片 | origin | sourceFileName | |||||||
'16' |
AcDbWipeout | 遮罩实体 | origin | sourceFileName | |||||||
'26' |
AcDbAttributeDefinition | 属性注记 | location | text | contents | height | rotate | horzMode | |||
'27' |
AcDbAttribute | 块属性 | location | text | contents | height | rotate | horzMode | |||
'28' |
AcDbTable | 表格 | positon | attributeDef | contents | rotate | scaleX | scaleY | scaleZ | ||
'29' |
AcDbMLeader | 引线标注 | location | contents | text | height | width | rotate | textHeight | actualHeight | actualWidth |
'30' |
AcDbRegion | 面域 | points | indices | data3d | area | perimeter | ||||
'31' |
AcDbPolyFaceMesh | 多面网格 | points | indices | data3d | ||||||
'32' |
AcDbPolygonMesh | 多边形网格 | points | indices | data3d | ||||||
'33' |
AcDbSurface | 曲面 | points | indices | data3d | ||||||
'34' |
AcDb3dSolid | 三维实体 | points | indices | data3d | ||||||
'35' |
AcDbFace | 三维面 | points | indices | data3d | ||||||
'36' |
AcDbSolid | 实线实体 | points | thickness | length | isclosed |
标注类(
'17'~'25')共用同一套专属字段:s3=location(标注点)、s4=text(标注文字)、n5=rotate、n6=measure(测量值)。 椭圆还有minorRadius(次半径)字段定义,但已超出n10列上限,查询结果中不出现。
字段含义速查(按字段名)
| 字段 | 类型 | 说明 |
|---|---|---|
points |
text | 坐标序列(x,y;x,y;...) |
center |
text | 圆 / 圆弧 / 椭圆中心点 |
location |
text | 文字插入点 |
positon |
text | 块 / 表格 / 型实体定位点(注:服务端拼写就是 positon) |
origin |
text | 栅格图片基点 |
area |
float | 面积 |
length |
float | 长度(直线 / 实体) |
radius |
float | 半径 |
startAngle / endAngle |
float | 圆弧 / 椭圆起止角 |
thickness |
float | 厚度 |
elevation |
float | 高度 |
isclosed |
float | 是否闭合(0/1) |
polyType |
float | 多段线类型 |
bulge |
text | 多段线凸度 |
text |
text | 文本内容(短) |
contents |
text | 多行文字(带样式) |
height |
float | 文字高(标注高) |
width |
float | 文字宽 |
rotate |
float | 旋转角度 |
textHeight / actualHeight / actualWidth |
float | 多行文字几何尺寸 |
horzMode |
float | 水平对齐模式 |
blockname |
text | 块名 |
attributeDef |
text | 块属性定义 |
scaleX / scaleY / scaleZ |
float | 块缩放 |
patternName |
text | 填充图案名 |
patternAngle / patternScale |
float | 填充角度 / 比例 |
majorAxis |
text | 椭圆长轴 |
normal |
text | 法向量 |
size |
float | 大小 |
isFit / fitTol / degree |
float | 样条拟合参数 |
indices |
text | 网格 / 面索引序列 |
data3d |
text | 3D 实体材质 / 顶点扩展 |
perimeter |
float | 面域周长 |
sourceFileName |
text | 栅格图片 / 遮罩的源文件名 |
textStyle |
text | 单行文本的文字样式名 |
radiusRatio |
float | 椭圆半径比(次轴/主轴) |
majorRadius |
float | 椭圆主轴半径(minorRadius 超出 n10 不上库) |
measure |
float | 标注测量值 |
lineTypeScale |
float | 多段线线型比例(注意大写 T;通用字段 n2 是 linetypeScale 小写 t,两者不同名) |
真实查询时不必死记字段对应。常见做法:先查少量数据
console.log一次,把字段名记下来再写正式代码。
五、SQL 条件示例(按场景分类)
5.1 按类型查
-- 所有直线
name='1'
-- 所有圆
name='7'
-- 所有圆弧 + 圆 + 椭圆
name='6' or name='7' or name='8'
-- 所有文字
name='12' or name='13' or name='26' or name='27'
-- 所有块参照
name='10'
5.2 类型 + 图层
-- 0 号图层的三维多段线
name='4' and layerindex=0
-- 0 / 1 / 3 号图层的所有圆
name='7' and (layerindex=0 or layerindex=1 or layerindex=3)
5.3 类型 + 颜色
-- 红色单行文字(0xFF0000FF -> -16776961)
name='13' and color=-16776961
-- 蓝色直线(0xFFFF0000 -> -65536)
name='1' and color=-65536
-- 不是黑色的所有文字
(name='12' or name='13') and color != -16777216
5.4 类型 + 几何属性
-- 长度为 10 的直线(n6 = length)
name='1' and n6=10
-- 长度大于 100 的直线
name='1' and n6 > 100
-- 半径为 5 的圆(n7 = radius)
name='7' and n7=5
-- 半径在 [10, 20] 之间的圆
name='7' and n7 >= 10 and n7 <= 20
-- 闭合的多段线(n6 = isclosed)
name='2' and n6=1
-- 面积 > 1000 的面域(n5 = area)
name='30' and n5 > 1000
5.5 类型 + 文字内容
-- 文字以 "DZ" 开头(s4 = text 字段)
name='13' and s4 like 'DZ%'
-- 文字长度 [2, 12] 且以 J 或 DZ 开头
(name='12' or name='13' or name='26' or name='27')
and LENGTH(s4) >= 2 and LENGTH(s4) <= 12
and (s4 like 'J%' or s4 like 'DZ%')
-- 多行文字内容包含"水泵"
name='12' and s4 like '%水泵%'
5.6 按 objectid 查
-- 指定 objectid(普通实体就是句柄;块内实体带 id 链和尾部标记)
objectid='1A'
objectid='9BE_5C_3F_#'
-- 块 EA / 10D / 19A 下所有子实体
objectid like 'EA_%' or objectid like '10D_%' or objectid like '19A_%'
-- 某个块的子实体
objectid like '9BE_%'
5.7 按块名查(块参照)
-- 块名为 "门" 的所有块参照(s5 = blockname)
name='10' and s5='门'
-- 块名以 "Door" 开头
name='10' and s5 like 'Door%'
5.8 按填充图案查
-- 填充图案为 ANSI31
name='11' and s4='ANSI31'
六、查询接口
6.1 条件查询 conditionQueryFeature
✅ 仅 GeomRender 可用(
objectid>0条件 + limit/beginpos 分页正常,见本文 §一)。返回{error:"not support query type!"}表示请求被路由到了内存进程(图是 Memory 方式打开,或请求里geom为 false)——显式传geom: true,并确认该图已以 GeomRender 方式打开过。
svc.conditionQueryFeature(param: IConditionQueryFeatures, cb?): Promise<any>;
interface IConditionQueryFeatures extends IQueryBaseFeatures {
/** SQL where 条件,必填 */
condition: string;
/** 矩形范围([x1,y1,x2,y2])或多边形点数组([[x,y],...])—— CAD 坐标 */
bounds?: [number, number, number, number] | [number, number][];
/** bounds 为点数组时,是否求交点;默认 false */
isGetIntersections?: boolean;
/** 起始记录位置(分页用)*/
beginpos?: number;
/** 是否包含几何信息(默认仅在 recordCount==1 时返回真实 geojson)*/
includegeom?: boolean;
/** 是否每条都返回真实几何 geojson(数据量大时慎用)*/
realgeom?: boolean;
/** 范围查询时:true=包含 / false=相交(默认)*/
isContains?: boolean;
}
最小用法:
const q = await svc.conditionQueryFeature({
condition: `name='13' or name='12' or name='26' or name='27'`,
fields: "objectid,text,location,envelop",
geom: true,
limit: 100000 // 默认 100,要全量必须放大
});
if (q.error) { console.error(q.error); return; }
console.log(q.recordCount, q.result);
带空间过滤:
// 矩形 + 类型
await svc.conditionQueryFeature({
condition: `name='7'`,
bounds: [100, 200, 500, 800],
isContains: false, // false=相交(默认);true=必须完全在矩形内
limit: 100000
});
// 多边形 + 类型
await svc.conditionQueryFeature({
condition: `name='10'`,
bounds: [[0,0],[100,0],[100,100],[0,100]],
isContains: true
});
6.2 点查询 pointQueryFeature
svc.pointQueryFeature(param: IPointQueryFeatures, cb?): Promise<any>;
interface IPointQueryFeatures extends IQueryBaseFeatures {
/** 查询点 X(CAD 坐标)*/
x: number;
/** 查询点 Y */
y: number;
/** 像素容差(屏幕几像素内都算命中)*/
pixelsize?: number;
/** 进一步用 SQL 过滤 */
condition?: string;
/** 单实体最大返回字节数(防 OOM)*/
maxGeomBytesSize?: number;
/** 一像素表示的几何长度(不传则按 zoom 算)*/
pixelToGeoLength?: number;
}
典型场景——鼠标点击选实体:
map.on("click", async (e) => {
const cad = map.fromLngLat(e.lngLat);
const q = await svc.pointQueryFeature({
x: cad.x, y: cad.y,
pixelsize: 5,
zoom: map.getZoom(),
limit: 20,
geom: true,
toMapCoordinate: true
});
console.log(q.result);
});
6.3 矩形查询 rectQueryFeature
svc.rectQueryFeature(param: IRectQueryFeatures, cb?): Promise<any>;
interface IRectQueryFeatures extends IQueryBaseFeatures {
/** 矩形左下点 X(不传则查整图)*/
x1?: number;
y1?: number;
/** 矩形右上点 X */
x2?: number;
y2?: number;
/** 进一步用 SQL 过滤 */
condition?: string;
/** 单实体最大几何字节 */
maxGeomBytesSize?: number;
}
await svc.rectQueryFeature({
x1: 0, y1: 0, x2: 1000, y2: 1000,
condition: `name='7'`,
limit: 100000,
geom: true
});
矩形查询也可改用
conditionQueryFeature({ bounds: [x1,y1,x2,y2] }),效果相同。
6.4 多边形查询
vjmap 没有独立的多边形查询接口,使用 conditionQueryFeature + bounds 数组:
await svc.conditionQueryFeature({
condition: `name='10'`,
bounds: [[100,100],[500,100],[500,500],[100,500]], // 多边形顶点
isContains: true // true=完全在多边形内;false=相交
});
6.5 分页查询(数据量大时必须)
limit 不能无限大,超过后台限制会被截断。万级以上结果集分页:
async function queryAll(condition, fields = "") {
const all = [];
let begin = 0;
while (true) {
const q = await svc.conditionQueryFeature({
condition, fields,
beginpos: begin,
limit: 10000 // 每次 1 万
});
if (q.error) throw new Error(q.error);
all.push(...(q.result || []));
begin += q.result.length;
if (all.length >= q.recordCount) break;
}
return all;
}
const lines = await queryAll(
`name='1' or name='2' or name='3' or name='4'`,
"objectid,points,envelop"
);
七、统一查询参数 IQueryBaseFeatures
所有查询接口都继承下面这组通用参数:
interface IQueryBaseFeatures {
/** 当前缩放级别(影响 pixel→几何转换、几何简化精度)*/
zoom?: number;
/** 地图 ID(不传则用当前已 open 的图)*/
mapid?: string;
/** 地图版本 */
version?: string;
/** 图层名 */
layer?: string;
/** 最大返回条数。条件/矩形默认 100,要全量必须自己设大;点查询默认只返回 1 条(Memory 下恒为 1) */
limit?: number;
/** 字段过滤,逗号分隔。如 "objectid,text,envelop"。空字符串 "" 表示返回所有字段。
既可写属性名(objectid/text/area),也可写原始列名 s1..s5 / n1..n10(结果里以列名为键)*/
fields?: string;
/** 是否走几何渲染空间库查询(不是"是否返回几何");不传时 SDK 取当前已打开图的打开方式。要几何用 includegeom/realgeom */
geom?: boolean;
/** GeoJSON 简化容差(墨卡托单位),减少传输量。0=不简化 */
simplifyTolerance?: boolean;
/** 启用查询缓存(仅内存模式) */
useCache?: boolean;
/** true=直接返回 CAD 坐标;false=返回墨卡托坐标(默认)*/
toMapCoordinate?: boolean;
}
字段过滤建议
不写 fields 会返回所有字段,移动端 / 弱网下流量大。建议明确列出:
// 只要 ID 和外包矩形
fields: "objectid,envelop"
// 文本类查询
fields: "objectid,text,location,height,rotate"
// 圆查询
fields: "objectid,center,radius,area"
八、查询返回结果字段
q.result[i] 中可能出现的字段(取决于 fields 与实体类型):
| 字段 | 类型 | 说明 |
|---|---|---|
objectid |
text | 实体唯一 ID(可作为 key) |
name |
text | 实体类型 ID(同上文) |
layerindex |
int | 图层索引 |
color |
int | 颜色(用 vjmap.entColorToHtmlColor() 转 HTML——要求 0xAABBGGRR 打包 32 位整数;小整数如 7 的 hex 不足 8 位会得到畸形 "#",见文末坑位) |
linetype |
text | 线型 |
linetypeScale |
float | 线型比例 |
lineWidth |
float | 线宽 |
alpha |
float | 透明度 |
xdata |
any | 扩展数据 |
bounds |
text | 外包矩形(CAD 坐标,[minx,miny,maxx,maxy] 字符串) |
envelop |
text | 外包矩形(墨卡托 WKT,map.getEnvelopBounds() 解析) |
geojson |
text | 真实几何 GeoJSON 字符串(默认原始墨卡托坐标;toMapCoordinate:true 时为 CAD 坐标;条件查询仅 includegeom:true 时才有值——不加 realgeom 时多条结果给的是外包矩形多边形;指定 fields 时须把 geojson 列进去) |
geom |
object | SDK _processQueryResult 转换后的几何(渲染经纬度,可直接进 source;isMapCoordinate 或 geojson 为空时不生成)——坐标空间细节见 coord/query-coords |
isEnvelop |
bool | 查询时是否仅给外包盒 |
points |
text | 坐标序列 x,y;x,y;... |
indices |
text | 索引序列(网格 / 面) |
center |
text | 圆心 |
radius |
float | 半径 |
startAngle / endAngle |
float | 弧度 |
area / length / perimeter |
float | 几何度量 |
isclosed |
bool | 是否闭合 |
text / contents |
text | 文本 |
height / width / textHeight / actualHeight / actualWidth |
float | 文字几何 |
rotate / scaleX / scaleY / scaleZ |
float | 块 / 表格变换 |
blockname |
text | 块名 |
location / positon / origin |
text | 位置点 |
normal |
text | 法向量 |
thickness / elevation |
float | 厚度 / 高程 |
bulge |
text | 多段线凸度 |
polyType |
float | 多段线类型 |
data3d |
text | 3D 材质 / 数据 |
majorAxis |
text | 椭圆长轴 |
u / v |
float | UV 坐标 |
size |
float | 大小 |
isFit / fitTol / degree |
float | 样条参数 |
horzMode |
float | 水平对齐 |
九、绘制查询结果到地图
9.1 用外包矩形画 Polygon(最快,适合大量结果高亮)
const polygons = q.result.map(r => ({
points: map.toLngLat(map.getEnvelopBounds(r.envelop).toPointArray()),
properties: {
id: r.objectid,
color: vjmap.entColorToHtmlColor(r.color),
text: r.text
}
}));
const layer = new vjmap.Polygon({
data: polygons,
fillColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'yellow', '#f0f'],
fillOpacity: ['case', ['to-boolean', ['feature-state', 'hover']], 0.6, 0.4],
fillOutlineColor: ['get', 'color'],
isHoverPointer: true,
isHoverFeatureState: true
});
layer.addTo(map);
layer.hoverFeatureState(e => {
if (e.features) {
map.logInfo(`选中 ${e.features[0].properties.id}: ${e.features[0].properties.text}`);
}
});
map.logInfo(text, type?):向document.body末尾追加#vjmapinfolog容器、内部每条消息是一个span.vjmapinfolog-{type}(type 如success)——不是挂在地图容器内的 DOM,自动化断言或截图取景时别在 map 容器里找它。同类logWarn/logError不存在,只有logInfo一个入口。
9.2 用真实几何画 GeoJSON 线 / 面
// 查询时加 includegeom:true + realgeom:true:SDK 已把每条几何转成渲染经纬度写到 r.geom
// ⚠️ 不要直接 JSON.parse(r.geojson) 进 source——那是原始墨卡托坐标,会全部出界
const fc = {
type: "FeatureCollection",
features: (q.result ?? []).filter(r => r.geom).map(r => ({
type: "Feature",
geometry: r.geom.geometries[0],
properties: { id: r.objectid }
}))
};
map.addSource("q", { type: "geojson", data: fc });
map.addLayer({
id: "q-line",
type: "line",
source: "q",
paint: { "line-color": "#ff0", "line-width": 2 }
});
9.3 中心点 Marker
for (const r of q.result) {
const center = map.getEnvelopBounds(r.envelop).center();
new vjmap.Marker()
.setLngLat(map.toLngLat(center))
.setPopup(new vjmap.Popup().setHTML(r.text || r.objectid))
.addTo(map);
}
9.4 批量定位 fitBounds
const all = new vjmap.GeoBounds();
for (const r of q.result) all.updateByBounds(map.getEnvelopBounds(r.envelop));
map.fitMapBounds(all, { padding: 80 });
9.5 闪烁定位(AI MCP 常用)
async function flashBounds(boundsArray) {
const pts = vjmap.GeoBounds.fromArray(boundsArray).toPointArray();
pts.push(pts[0]);
const layer = new vjmap.Polyline({
data: [{ points: map.toLngLat(pts), properties: { opacity: 1 } }],
lineColor: "yellow",
lineWidth: 3,
lineOpacity: ["get", "opacity"]
});
layer.addTo(map);
await new Promise(resolve => vjmap.createAnimation({
from: 1, to: 10, duration: 1000,
onUpdate: v => {
const data = layer.getData();
data.features[0].properties.opacity = parseInt(v) % 2;
layer.setData(data);
},
onComplete: () => { layer.remove(); resolve(); }
}));
}
十、典型完整示例
10.1 查所有文字并高亮
const { entTypeIdMap } = await svc.getConstData();
const idOf = name => Object.keys(entTypeIdMap).find(k => entTypeIdMap[k] === name);
const cond = ['AcDbText','AcDbMText','AcDbAttributeDefinition','AcDbAttribute']
.map(n => `name='${idOf(n)}'`).join(' or ');
const q = await svc.conditionQueryFeature({
condition: cond,
fields: "objectid,text,envelop,color",
geom: true,
limit: 100000
});
if (q.error) return message.error(q.error);
const polygons = q.result.map(r => ({
points: map.toLngLat(map.getEnvelopBounds(r.envelop).toPointArray()),
properties: {
id: r.objectid,
color: vjmap.entColorToHtmlColor(r.color),
text: r.text
}
}));
new vjmap.Polygon({
data: polygons,
fillColor: '#f0f', fillOpacity: 0.4,
fillOutlineColor: ['get', 'color']
}).addTo(map);
10.2 查指定块下的所有子实体(取面积最大的)
const blockObjectId = '9BE';
const sub = await svc.conditionQueryFeature({
condition: `objectid like '${blockObjectId}_%'`,
fields: "objectid,name,n5", // n5 对多段线 / 圆 / 面域 = area
limit: 100000
});
const max = sub.result.reduce((a, b) => (a?.n5 || 0) > (b?.n5 || 0) ? a : b);
console.log("最大子实体:", max);
10.3 查鼠标点击附近的圆并高亮半径
map.on("click", async e => {
const cad = map.fromLngLat(e.lngLat);
const q = await svc.pointQueryFeature({
x: cad.x, y: cad.y,
pixelsize: 5,
condition: `name='7'`, // 限定只查圆
fields: "objectid,center,radius",
zoom: map.getZoom(),
toMapCoordinate: true,
limit: 5
});
q.result.forEach(c => console.log(`圆 ${c.objectid}: 半径 ${c.radius}`));
});
10.4 分页查所有横竖直线
const queryEntTypes = ['AcDbLine','AcDbPolyline','AcDb2dPolyline','AcDb3dPolyline'];
const cond = queryEntTypes.map(t => `name='${idOf(t)}'`).join(' or ');
const result = [];
let begin = 0;
while (true) {
const q = await svc.conditionQueryFeature({
condition: cond,
fields: "objectid,points,envelop",
beginpos: begin,
limit: 100000
});
if (q.error) break;
result.push(...(q.result || []));
begin += q.result.length;
if (result.length >= q.recordCount) break;
}
// 过滤纯横竖
const hvLines = result.filter(e => {
const pts = e.points.split(";");
if (pts.length !== 2) return false;
const [a, b] = pts.map(p => vjmap.geoPoint(p.split(",")));
return vjmap.isZero(a.x - b.x) || vjmap.isZero(a.y - b.y);
});
十一、性能建议
fields越少越快。大数据查询禁用*,只列必要字段。- 不要用
geom: false省流量——它会把查询路由到内存进程(条件查询直接报not support query type!);省流量靠精简fields、不传includegeom。 - 大结果集必须分页(
limit+beginpos),避免一次性请求百万记录。 realgeom: true仅在数量少(<= 几百)时用;批量结果用envelop即可,足以做高亮 / 定位。- 绘制结果用
Polygon/Polyline一次setData,不要循环addTo。 - 动态查询前
await map.onLoad(),否则addLayer报错。 - 能用 SQL 范围过滤就别全量后再过滤:
bounds让后台空间索引发挥作用。 color字段用整数比较,不要在 SQL 里转换 RGB 字符串。
十二、常见坑
name=1查不到结果 →name是字符串字段,必须name='1'。color=0xFF0000FF写成正数没结果 → 后台保存的是 32 位有符号整数,红色用-16776961。- 拿到
envelop直接当 CAD 坐标 → 它是墨卡托 WKT,必须map.getEnvelopBounds(envelop)转 CAD。 - 用
name=10期望查到块的子实体 →name='10'只是块参照本身;子实体是块定义里的实体,要用objectid like '块id_%'。 limit没传 → 默认只返回 100 条(点查询只返回 1 条),业务上易误判"图里只有 100 条"。- 多图并存时忘指定
mapid→ 查到的是当前 open 的图。查非当前图时必须同时传mapid、geom: true、layer: await svc.getStyleLayerName(mapid)——否则 SDK 沿用当前图的样式图层名,服务端找不到该样式静默返回{};或按当前图的打开方式填geom,被路由到内存进程报not support query type!。 isContains: true漏实体 → 完全包含很严格,稍微越界就不算。一般false(相交)符合直觉。fields: ""期望返回所有字段 → 是的,空字符串等价于全字段,但写null或不传也是同样效果。- 拼 SQL 时把用户输入直接拼接 → SQL 注入风险。SDK 没有内置防护,需要自己做白名单 / 转义。
- 几何渲染图却用
exprQueryFeature全表扫 → 性能差。能用 SQL 一定用 query-sql 走空间库。 - 多版本下没传
version→ 拿到的是当前版本;老版本数据要显式version: "v2"。 objectid当成数字 → 它是字符串(如"1A"、"9BE_5C_3F_#"、"5C$2A"),业务里始终当字符串处理。- 服务端字段拼写:
positon(不是position)、bulge(多段线凸度)等,写 SQL 时容易拼错。 entColorToHtmlColor(小整数)得畸形"#"→ 实现把数字按(c>>>0).toString(16)后定长 8 位切片(0xAABBGGRR打包布局)。后端color字段是打包好的 int32(如-65536)→ 正常;自己传小整数(如7)hex 不足 8 位、切片全空 → 返回"#"。字符串颜色原样返回;#757675有 darkMode 特判。getEnvelopBounds的 WKT 解析很脆→ 实现是replace("POLYGON((","")精确串匹配 + 只取前 4 个坐标点。带空格的POLYGON ((...))、孔洞、多边形顶点 ≠4 都会解析错。仅信任conditionQueryFeature返回的envelop格式,别拿它解通用 WKT。
十三、相关文档
- query-sql:SQL 查询接口快速速查(与本文互补)
- query-expression:表达式查询(内存模式 / 复杂逻辑)
- query-cases:综合查询用例(自动分图 / 提表 / 中心线)
- query-fulltext:跨图全文搜索
- svr-style-var:服务端条件高亮 / 过滤(不查询、直接出样式)
- rest-interface:REST 接口直接调用
- common-map-methods:
svc.openMap/getConstData等基础 - 官网原文:https://vjmap.com/guide/dataQuery.html / https://vjmap.com/guide/svrStyleVar.html