# 地图服务

[Service](https://vjmap.com/map3d/api/classes/Service.html) 服务主要用于上传、打开CAD图、图层管理、样式等相关服务。

::: warning
连接试用版本的唯杰地图服务将会有水印

如果不连接服务或连接失败，将禁止使用

如需去除水印，请联系客服私有化部署正式版本
:::


## 常用方法

|方法|描述|
|:---|:---|
|[clone](https://vjmap.com/map3d/api/classes/Service.html#clone)|克隆一个新的服务实例对象|
|[serviceUrl](https://vjmap.com/map3d/api/classes/Service.html#serviceUrl)|得到服务地址|
|[switchWorkspace](https://vjmap.com/map3d/api/classes/Service.html#switchWorkspace)|切换至工作区|
|[getCurWorkspaceName](https://vjmap.com/map3d/api/classes/Service.html#getCurWorkspaceName)|获取当前的工作区名称|
|[getWorkspaces](https://vjmap.com/map3d/api/classes/Service.html#getWorkspaces)|获取所有工作区|
|[workspaceCreate](https://vjmap.com/map3d/api/classes/Service.html#workspaceCreate)|创建工作区|
|[workspaceModify](https://vjmap.com/map3d/api/classes/Service.html#workspaceModify)|修改工作区|
|[workspaceDelete](https://vjmap.com/map3d/api/classes/Service.html#workspaceDelete)|删除工作区|
|[pwdToSecretKey](https://vjmap.com/map3d/api/classes/Service.html#pwdToSecretKey)|密码转换为秘钥|
|[addSecretKey](https://vjmap.com/map3d/api/classes/Service.html#addSecretKey)|增加秘钥key|
|[removeSecretKey](https://vjmap.com/map3d/api/classes/Service.html#removeSecretKey)|移除秘钥key|
|[addAccessKey](https://vjmap.com/map3d/api/classes/Service.html#addAccessKey)|增加访问key|
|[removeAccessKey](https://vjmap.com/map3d/api/classes/Service.html#removeAccessKey)|移除访问key|
|[setCurrentMapParam](https://vjmap.com/map3d/api/classes/Service.html#setCurrentMapParam)|设置打开地图参数|
|[currentMapParam](https://vjmap.com/map3d/api/classes/Service.html#currentMapParam)|当前地图参数|
|[openMap](https://vjmap.com/map3d/api/classes/Service.html#openMap)|打开图|
|[updateMap](https://vjmap.com/map3d/api/classes/Service.html#updateMap)|更新地图|
|[glyphsUrl](https://vjmap.com/map3d/api/classes/Service.html#glyphsUrl)|字体地址|
|[baseUrl](https://vjmap.com/map3d/api/classes/Service.html#baseUrl)|服务根地址|
|[spriteUrl](https://vjmap.com/map3d/api/classes/Service.html#spriteUrl)|精灵图片名称|
|[setSprite](https://vjmap.com/map3d/api/classes/Service.html#setSprite)|设置精灵图片名称|
|[blankTileUrl](https://vjmap.com/map3d/api/classes/Service.html#blankTileUrl)|空白瓦片地址|
|[qrcodeUrl](https://vjmap.com/map3d/api/classes/Service.html#qrcodeUrl)|二维码图片地址|
|[rasterTileUrl](https://vjmap.com/map3d/api/classes/Service.html#rasterTileUrl)|栅格瓦片地址|
|[vectorTileUrl](https://vjmap.com/map3d/api/classes/Service.html#vectorTileUrl)|矢量瓦片地址|
|[checkFileHasUpload](https://vjmap.com/map3d/api/classes/Service.html#checkFileHasUpload)|检查文件是否上传过|
|[uploadUrl](https://vjmap.com/map3d/api/classes/Service.html#uploadUrl)|返回上传文件的url地址|
|[strMd5](https://vjmap.com/map3d/api/classes/Service.html#strMd5)|获取字符串的Md5值|
|[styleVersion](https://vjmap.com/map3d/api/classes/Service.html#styleVersion)|得到style的版本号|
|[fileMd5](https://vjmap.com/map3d/api/classes/Service.html#fileMd5)|获取文件的Md5值|
|[uploadMap](https://vjmap.com/map3d/api/classes/Service.html#uploadMap)|上传地图|
|[execCommand](https://vjmap.com/map3d/api/classes/Service.html#execCommand)|执行命令|
|[metadata](https://vjmap.com/map3d/api/classes/Service.html#metadata)|获取地图元数据|
|[updateMetadata](https://vjmap.com/map3d/api/classes/Service.html#updateMetadata)|修改地图元数据|
|[listMaps](https://vjmap.com/map3d/api/classes/Service.html#listMaps)|获取所有地图信息|
|[waitMapOpenFinish](https://vjmap.com/map3d/api/classes/Service.html#waitMapOpenFinish)|等待地图打开完成|
|[processQueryResult](https://vjmap.com/map3d/api/classes/Service.html#processQueryResult)|处理查询结果|
|[pointQueryFeature](https://vjmap.com/map3d/api/classes/Service.html#pointQueryFeature)|点查询实体|
|[rectQueryFeature](https://vjmap.com/map3d/api/classes/Service.html#rectQueryFeature)|矩形查询实体|
|[exprQueryFeature](https://vjmap.com/map3d/api/classes/Service.html#exprQueryFeature)|表达式查询实体|
|[conditionQueryFeature](https://vjmap.com/map3d/api/classes/Service.html#conditionQueryFeature)|条件查询实体|
|[getMapLayers](https://vjmap.com/map3d/api/classes/Service.html#getMapLayers)|得到地图图层集合|
|[cmdSwitchLayers](https://vjmap.com/map3d/api/classes/Service.html#cmdSwitchLayers)|切换图层|
|[cmdUpdateStyle](https://vjmap.com/map3d/api/classes/Service.html#cmdUpdateStyle)|更新样式|
|[cmdSliceLayer](https://vjmap.com/map3d/api/classes/Service.html#cmdSliceLayer)|对图层进行切片缓存|
|[createStyle](https://vjmap.com/map3d/api/classes/Service.html#createStyle)|获取样式图层名|
|[cmdGetDrawBounds](https://vjmap.com/map3d/api/classes/Service.html#cmdGetDrawBounds)|获取图形中有数据的范围区域|
|[getStyleLayerName](https://vjmap.com/map3d/api/classes/Service.html#getStyleLayerName)|获取样式图层名|
|[thumbnailUrl](https://vjmap.com/map3d/api/classes/Service.html#thumbnailUrl)|获取图的缩略图|
|[wmsTileUrl](https://vjmap.com/map3d/api/classes/Service.html#wmsTileUrl)|wms服务瓦片地址|
|[cmdDeleteMap](https://vjmap.com/map3d/api/classes/Service.html#cmdDeleteMap)|删除地图|
|[cmdGetAccessKey](https://vjmap.com/map3d/api/classes/Service.html#cmdGetAccessKey)|获取地图的AccessKey|
|[cmdResetAccessKey](https://vjmap.com/map3d/api/classes/Service.html#cmdResetAccessKey)|重置地图的AccessKey|
|[cmdSetMapPassword](https://vjmap.com/map3d/api/classes/Service.html#cmdSetMapPassword)|重置地图的密码|
|[cmdRenameMap](https://vjmap.com/map3d/api/classes/Service.html#cmdRenameMap)|地图ID重命名|
|[cmdClearMapCache](https://vjmap.com/map3d/api/classes/Service.html#cmdClearMapCache)|清空地图的几何和瓦片缓存数据|
|[cmdClearTileCache](https://vjmap.com/map3d/api/classes/Service.html#cmdClearTileCache)|清空地图的瓦片缓存数据|
|[cmdDeleteStyle](https://vjmap.com/map3d/api/classes/Service.html#cmdDeleteStyle)|删除地图样式|
|[cmdDeleteCache](https://vjmap.com/map3d/api/classes/Service.html#cmdDeleteCache)|删除地图缓存|
|[cmdRunStatus](https://vjmap.com/map3d/api/classes/Service.html#cmdRunStatus)|获取当前运行状态|
|[cmdGetSupportFormat](https://vjmap.com/map3d/api/classes/Service.html#cmdGetSupportFormat)|获取支持的格式类型|
|[getConstData](https://vjmap.com/map3d/api/classes/Service.html#getConstData)|获取服务后台常量设置|
|[rasterBlankStyle](https://vjmap.com/map3d/api/classes/Service.html#rasterBlankStyle)|空白栅格style|
|[rasterLayerId](https://vjmap.com/map3d/api/classes/Service.html#rasterLayerId)|获取栅格图层ID|
|[rasterSourceId](https://vjmap.com/map3d/api/classes/Service.html#rasterSourceId)|获取栅格源ID|
|[rasterStyle](https://vjmap.com/map3d/api/classes/Service.html#rasterStyle)|栅格style|
|[vectorStyle](https://vjmap.com/map3d/api/classes/Service.html#vectorStyle)|矢量style|
|[getFontsCapacity](https://vjmap.com/map3d/api/classes/Service.html#getFontsCapacity)|得到所有矢量字体名称|
|[clearCache](https://vjmap.com/map3d/api/classes/Service.html#clearCache)|清空服务器缓存数据|
|[webMapUrl](https://vjmap.com/map3d/api/classes/Service.html#webMapUrl)|获取服务器地图服务地址|
|[composeNewMap](https://vjmap.com/map3d/api/classes/Service.html#composeNewMap)|组合成新地图|
|[cmdMapDiff](https://vjmap.com/map3d/api/classes/Service.html#cmdMapDiff)|比较地图不同|
|[cmdExportLayout](https://vjmap.com/map3d/api/classes/Service.html#cmdExportLayout)|导出布局空间为dwg图|
|[cmdMatchObject](https://vjmap.com/map3d/api/classes/Service.html#cmdMatchObject)|目标匹配|
|[cmdCreateEntitiesGeomData](https://vjmap.com/map3d/api/classes/Service.html#cmdCreateEntitiesGeomData)|获取创建实体的几何数据|
|[cmdTransform](https://vjmap.com/map3d/api/classes/Service.html#cmdTransform)|坐标转换|
|[cmdPrjWktToPrj4](https://vjmap.com/map3d/api/classes/Service.html#cmdPrjWktToPrj4)|投影prj文件WKT字符转proj4字符串|
|[saveCustomData](https://vjmap.com/map3d/api/classes/Service.html#saveCustomData)|保存用户自定义数据|
|[getCustomData](https://vjmap.com/map3d/api/classes/Service.html#getCustomData)|获取用户自定义数据|
|[getCustomDataKeysByPrefix](https://vjmap.com/map3d/api/classes/Service.html#getCustomDataKeysByPrefix)|通过前缀获取用户自定义数据的键值|
|[deleteCustomData](https://vjmap.com/map3d/api/classes/Service.html#deleteCustomData)|删除用户自定义数据|
|[toDbDoc](https://vjmap.com/map3d/api/classes/Service.html#toDbDoc)|转成文档字符串|


## 基本用法

打开一个CAD图
```js
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在，可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
```



<mapFrame>
<pre>
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在，可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
</pre>
</mapFrame>


## CAD图层切换
<mapFrame>
<pre>
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在，可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
// 获取cad图层
let layers = svc.getMapLayers();
const ui = await app.getConfigPane({ title: "关闭图层", style: { width: "250px"}});
let gui = new vjmap3d.UiPanelJsonConfig();
for(let n = 0; n < layers.length; n++) {
    gui.add(layers[n], "isOff").label(layers[n].name).onChange(async () => {
        await svc.cmdSwitchLayers(layers.reduce((sum, val) => {
            if (!val.isOff) {
                sum.push(val.name);
            }
            return sum;
        }, []))
        let newProvider = new vjmap3d.MapProvider(
            [
                {
                    url: app.svc.rasterTileUrl()
                }
            ],
            {
                transparent: true
            }
        );
        mapviewEnt.setProvider(newProvider)
    })
}
gui.toJson().forEach(c => ui.appendChild(c));
</pre>
</mapFrame>





## CAD数据查询矢量绘制

<mapFrame>
<pre>
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
const MAP_DEFAULT_SIZE = 200;
let res = await svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在，可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle() // div为深色背景颜色时，这里也传深色背景样式
});
if (res.error) {
    showError(res.error);
    return;
}
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds);
app.centerOrigin = new THREE.Vector3(mapBounds.center().x, 0, mapBounds.center().y);
app.scaleOrigin = MAP_DEFAULT_SIZE / mapBounds.width();
const queryMapData = async () => {
    let cadPrj = new vjmap3d.GeoProjection(mapBounds);
    res = await svc.conditionQueryFeature({
        condition: `1 == 1`, // 只需要写sql语句where后面的条件内容,字段内容请参考文档"服务端条件查询和表达式查询"
        fields: "",
        includegeom: true, // 是否返回几何数据,为了性能问题，realgeom为false时，如果返回条数大于1.只会返回每个实体的外包矩形，如果条数为1的话，会返回此实体的真实geojson；realgeom为true时每条都会返回实体的geojson
        realgeom: true,
        limit: 1000000 //设置很大,不传的话，默认只能取100条
    }, pt => {
        // 查询到的每个点进行坐标处理回调
        return cadPrj.fromMercator(pt);// 转成cad的坐标
    })
    if (res.error) {
        showError(res.error)
        return
    } else {
        if (res && res.result && res.result.length > 0) {
            let idx = 0;
            let features = [];
            for (let row of res.result) {       // row：查询返回的数据行，非 Entity
                if (row.geom && row.geom.geometries) {
                    // 实体颜色为 0xAABBGGRR 整数(BGR序)，转成 #RRGGBB
                    let hex = (row.color >>> 0).toString(16).padStart(8, "0");
                    let clr = "#" + hex.substring(6, 8) + hex.substring(4, 6) + hex.substring(2, 4);
                    for (let g = 0; g < row.geom.geometries.length; g++) {
                        features.push({
                            id: idx++,
                            type: "Feature",
                            properties: {
                                objectid: row.objectid,
                                color: clr,
                                alpha: row.alpha / 255,
                                lineWidth: 1,
                                name: row.name,
                                isline: row.isline,
                                layerindex: row.layerindex
                            },
                            geometry: row.geom.geometries[g]
                        })
                    }
                }
            }
            let geom = {
                type: "FeatureCollection",
                features: features
            };
            return geom;
        }
    }
}
let geojson = await queryMapData();
let dataPolyline = [];
let dataPolygon = [];
for (let i = 0; i < geojson?.features.length; i++) {
    let feature = geojson?.features[i];
    if ((feature.geometry.type == "LineString")) {
        dataPolyline.push({
            coordinates: feature.geometry.coordinates.map(c => vjmap3d.toWorld([c[0], c[1]]).toArray()),
            color: feature.properties.color,
            id: feature.id,
            lineWidth:  1,
            opacity: feature.properties.alpha,
            dashSize: 0.2,
            gapSize: 0.2,
            dashed: false,
            objectid: feature.properties.objectid
        })
    } else if ((feature.geometry.type == "Polygon")) {
        dataPolygon.push({
            coordinates: feature.geometry.coordinates.map(c => c.map(s => {
                let vec3 = vjmap3d.toWorld([s[0], s[1]]).toArray();
                return [vec3[0], vec3[2]]
            })),
            color: feature.properties.color,
            id: feature.id,
            opacity: feature.properties.alpha,
            objectid: feature.properties.objectid,
            extrude: {
                depth: 2
            }
        })
    }
}
let polylines = new vjmap3d.PolylinesEntity({
    data: dataPolyline,
    highlightStyle: {
        vertexColors: false,
        color: 0xFFFF00
    },
})
polylines.addTo(app);
polylines.pointerEvents = true;
// 
let hoverVertexPointData = [];
let hoverVertexSymbol = new vjmap3d.SymbolEntity({
    data: hoverVertexPointData,
    style: {
        size: 13,
        shape: "circle",
        color: "#0f0",
        borderColor: "#f00",
        transparent: true,
        opacity: 1,
        borderWidth: 3,
        sizeAttenuation: false,
        vertexBorderColor: false,
        vertexColors: false,
        vertexSize: false
    }
});
hoverVertexSymbol.addTo(app);
// 
polylines.on("mouseover", e => {
    if (e?.intersection?.faceIndex !== undefined) {
        let itemData = polylines.getItemDataByFaceIndex(e?.intersection?.faceIndex);
        if (itemData) {
            // objectid相同的都选上
            let entities = polylines.getData().filter(item => item.objectid == itemData.objectid)
            entities.forEach(e => e.id !==undefined &&  polylines.setItemHighlight(e.id, true))
        }
    } else if (e?.intersection?.index !== undefined) {
        let itemData = polylines.getVertexSymbol().getItemDataByPointIndex(e?.intersection?.index);
        if (!itemData) return;
        let pointData = {...itemData};
        pointData.size = (pointData.size ?? 10) + 3;
        // 顶点
        hoverVertexSymbol.setData([
            pointData
        ])
    }                  
})
polylines.on("mouseout", e => {
    polylines.clearHighlight()
    hoverVertexSymbol.setData([])
})
// 
let polygons = new vjmap3d.FillExtrusionsEntity({ // PolygonsEntity
    data: dataPolygon ,
    showVertex: false,
})
polygons.addTo(app)
//
polygons.pointerEvents = true;
polygons.on("mouseover", e => {
    console.log(e)
    if (e?.intersection?.faceIndex !== undefined) {
        let itemData = polygons.getItemDataByFaceIndex(e?.intersection?.faceIndex);
        if (itemData) {
            // objectid相同的都选上
            let entities = polygons.getData().filter(item => item.objectid == itemData.objectid)
            entities.forEach(e => e.id !==undefined && polygons.setItemHighlight(e.id, true))
        }
    }
})
polygons.on("mouseout", e => {
    polygons.clearHighlight()
})
</pre>
</mapFrame>
