数据加载
需要启用模型平移插件
通用代码
获取加载参数
通过数据的 id 进行数据加载。数据的 id 可从数据列表中获取。
ts
// 通过数据的 id 进行数据加载,获取上传参数
const { data } = await getDataInfo({ id: '89ae976b54517804316a83e79dbcada0' })
const { bizType, fileType, id, jsonPath, position, name } =
getPreviewParams(data)
const res = await getServiceAttr({ folderId: id })
const attrData = res.data?.[0]
const attr = getAttrJson(attrData) //素材属性对象,无属性时为空对象
const coverImg = attrData?.coverImg //缩略图路径
/**
* 获取数据详情
* @param params 数据id
*/
function getDataInfo(params: { id: string }) {
return request({
url: '/admin/tx/data/info',
method: 'get',
params
})
}
/**
* 获取加载参数
* @param data 来自数据列表
*/
function getPreviewParams(data: any) {
return {
bizType: data.bizType,
jsonPath: `/api/admin/tx/preview/data/index/${data.id}?token=${CONSTANTS.TOKEN}`,
fileType: data.fileType,
id: data.id,
position: data.position,
name: data.name
}
}
/**获取素材属性-用于保存位置、样式 */
function getServiceAttr(params: { folderId: string }) {
return request({
url: '/admin/tx/service/attr/get',
method: 'get',
params
})
}
/**获取素材属性JSON */
function getAttrJson<T = Record<any, any>>(dataObj?: Record<string, any>) {
if (!dataObj) return {} as T
const attr = (() => {
try {
return JSON.parse(decodeURIComponent(dataObj?.attrJson))
} catch (error) {
return {} as T
}
})()
return {
...attr
} as T
}
/**保存/更新素材属性 */
function saveServiceAttr(data: {
attrJson?: string //属性json
coverImg?: string //缩略图路径
folderId: string //数据id
id?: string //属性对象的id
}) {
return request({
url: '/admin/tx/service/attr/save',
method: 'post',
data
})
}
/**上传图片
* @param data.folderId //传递文件的id
* @param data.imageBase64Code//base64编码,必须为jpeg格式
*/
function serviceAttrUploadTempImg(data: {
folderId: string
imageBase64Code: string
}) {
return request({
url: '/admin/tx/service/attr/uploadTempImg',
method: 'post',
data
})
}
保存素材属性通用
保存素材属性,这里保存的属性会在场景初始加载时使用。
ts
/**
* 保存素材属性
* @param attrJson 素材属性对象,不同的素材类型属性不同,见下文各个素材类型的属性类型
*/
async function saveAttr<T>(attrJson: T) {
const coverImg = await serviceAttrUploadTempImg({
folderId: id,
imageBase64Code: 'data:image/jpeg;base64,someBase64Code' //base64编码,必须为jpeg格式
})
//获取之前保存的样式Id,如果没有则为undefined
const attrId = await (async () => {
const getAttrRes = await getServiceAttr({
folderId: formModel.id ?? ''
})
return getAttrRes.data?.[0]?.id
})()
//id为空时为新增,否则为更新
await saveServiceAttr({
folderId: formModel.id ?? '',
id: attrId,
coverImg: cover_img,
attrJson: encodeURIComponent(JSON.stringify(attrJson))
})
}
影像
bizType |
---|
1 |
影像属性类型
ts
type imageryAttributes = {
attachType: number //1:依模型 0:依地表
opacity: number //透明度 0-100; 百分比
}
加载影像
加载影像,返回影像图层对象进行后续操作
加载影像需要的参数
ts
/**
* 加载影像
* @param id 数据id
* @param jsonPath 影像json路径
* @param subdomains 子域(不必填)
*/
async function loadImagery(
{
id,
jsonPath,
subdomains
}: {
id: string
jsonPath: string
subdomains?: string[]
} = {
subdomains: []
}
) {
const { imageryLayers } = viewer
const params: any = {
url: jsonPath
}
if (subdomains.length > 0) {
params.baseUri = 'http://{s}/' + id + '/{z}/{x}/{y}.png'
params.subdomains = subdomains
}
try {
// @ts-ignore
const lsImageryProvider = await LSGlobe.LSImageryProvider.fromUrl(
params.url,
params
)
const imageryLayer = imageryLayers.addImageryProvider(lsImageryProvider, 3)
const flyFn = () => viewer!.flyTo(imageryLayer)
flyFn()
return { imageryLayer }
} catch (error) {
console.error(`Error loading imagery: ${error}`)
}
return {
imageryLayer: null
}
}
加载样式
加载样式使用类型
ts
init_imagery_style(imageryLayer, attr)
function init_imagery_style<T extends imageryAttributes>(
imageryLayer: any,
attr: T
) {
imageryLayer.alpha = (attr.opacity ?? 100) / 100
}
保存属性
ts
saveAttr<imageryAttributes>({
attachType: 1,
opacity: 100
})
地形
bizType |
---|
2 |
地形属性类型
无
加载地形
加载地形需要的参数
ts
/**
* 加载地形
* @param id 数据id
* @param jsonPath 地形json路径
* @param subdomains 子域(不必填)
*/
async function loadTerrain(
{
id,
jsonPath,
subdomains
}: {
id: string
jsonPath: string
subdomains?: string[]
} = {
subdomains: []
}
) {
// @ts-ignore
const { terrainLayers } = viewer
const params: any = {
url: jsonPath
}
if (subdomains.length > 0) {
params.baseUri = 'http://{s}/' + id + '/{z}/{x}/{y}.png'
params.subdomains = subdomains
}
try {
const lsTerrainProvider = await LSGlobe.LSTerrainProvider.fromUrl(
jsonPath,
params
)
terrainLayers.addTerrainProvider(lsTerrainProvider)
const flyFn = () => {
viewer!.camera.flyTo({
destination: lsTerrainProvider._rectangle
})
}
flyFn()
} catch (error) {
console.error(`Error loading Terrain: ${error}`)
}
}
加载样式
无
保存属性
保存属性使用方法/类型
ts
saveAttr({})
倾斜模型
bizType |
---|
3 |
倾斜模型属性类型
ts
type obliqueModelAttributes = {
lon: number // 经度
lat: number // 纬度
height: number // 海拔高度
opacity: number // 不透明度0-100 百分比
granularity: number // 精细度0-16
modelMatrix: number[] //模型矩阵
}
加载倾斜模型
通用的加载函数,bizType 为 3 /4/ 5 时调用此函数
加载倾斜模型需要的参数
ts
/**
* 加载倾斜模型
* @param id 数据id
* @param jsonPath 倾斜模型json路径
* @param bizType 数据bizType
*/
async function loadArtificialModel({ id, position, jsonPath, bizType }) {
try {
const tileset = await (LSGlobe.Cesium3DTileset as any).fromUrl(jsonPath, {
skipLevelOfDetail: true
})
viewer!.scene.primitives.add(tileset)
if (5 == bizType) {
processTileset(tileset)
} else if (3 == bizType) {
tileset.cacheBytes = 1024 * 1024 * 1024 * 1
}
const addpointStrs = position
? position.split(',')?.map((e) => Number(e))
: getTileSetPosition(tileset)
//等待200ms
await (() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 200)
})
})()
const flyFn = () => {
viewer!.camera.flyToBoundingSphere(tileset.boundingSphere)
viewer!.camera.lookAtTransform(LSGlobe.Matrix4.IDENTITY)
}
flyFn()
return { tileset, tilesetPosition: addpointStrs }
} catch (error) {
console.error(`Error loading tileset: ${error}`)
}
return {
tileset: null,
tilesetPosition: [120, 30, 0]
}
/**
* 处理Tileset
* 同一个DbId对应的集合
*/
function processTileset(tileset: any) {
var _hiddenDbIds = []
/**
* 获取DbId
* @param {*} feature
*/
function getFeatureDbId(feature: any) {
if (LSGlobe.defined(feature) && LSGlobe.defined(feature.getProperty)) {
return parseInt(feature.getProperty('DbId'), 10)
}
return -1
}
function unloadFeature(_feature: any) {}
function loadFeature(feature: any) {
const dbId = getFeatureDbId(feature)
// 存储dbId和feature的映射关系
if (!tileset.dbIdToFeatures) tileset.dbIdToFeatures = {}
let features = tileset.dbIdToFeatures[dbId]
if (!LSGlobe.defined(features)) {
tileset.dbIdToFeatures[dbId] = features = []
}
features.push(feature)
}
function processContentFeatures(content: any, callback: any) {
const featuresLength = content.featuresLength
for (let i = 0; i < featuresLength; ++i) {
const feature = content.getFeature(i)
callback(feature)
}
}
function processTileFeatures(tile: any, callback: any) {
const content = tile.content
const innerContents = content.innerContents
if (LSGlobe.defined(innerContents)) {
const length = innerContents.length
for (let i = 0; i < length; ++i) {
processContentFeatures(innerContents[i], callback)
}
} else {
processContentFeatures(content, callback)
}
}
tileset.tileLoad.addEventListener(function (tile: any) {
processTileFeatures(tile, loadFeature)
})
tileset.tileUnload.addEventListener(function (tile: any) {
processTileFeatures(tile, unloadFeature)
})
}
function getTileSetPosition(tileset: any) {
//用模型编辑器获取(目前获取的是建模原点的位置)
const getPositionByModelEditor = () => {
viewer!.boxEditBoxGeometry.viewModel.editObject = tileset
const pos = cloneDeep(viewer!.boxEditBoxGeometry.viewModel.position)
viewer!.boxEditBoxGeometry.viewModel.editObject = null
return [pos.x, pos.y, pos.z]
}
return getPositionByModelEditor()
}
}
加载样式
加载样式使用方法
ts
init_obliqueModel_style(tileset, attr)
function init_obliqueModel_style<T extends obliqueModelAttributes>(
tileset: any,
attr: T
) {
if (attr.modelMatrix) {
tileset.modelMatrix = LSGlobe.Matrix4.fromArray(attr.modelMatrix)
}
tileset.style = new LSGlobe.Cesium3DTileStyle({
color: "color('rgba(255,255,255," + (attr.opacity ?? 100) / 100 + ")')"
})
tileset.maximumScreenSpaceError = attr.granularity
}
保存属性
ts
/**获取经纬高 */
const { lon, lat, height } = (() => {
const formModel = {
lon: 120,
lat: 30,
height: 0
}
viewer.boxEditBoxGeometry.viewModel.editObject = formModel.tileset
viewer.boxEditBoxGeometry.viewModel.move()
const pos = viewer!.boxEditBoxGeometry.viewModel.position
formModel.lon = pos.x
formModel.lat = pos.y
formModel.height = pos.z
viewer!.boxEditBoxGeometry.viewModel.editObject = null
return formModel
})()
saveAttr<obliqueModelAttributes>({
lon: lon,
lat: lat,
height: height,
opacity: 100,
granularity: 10,
modelMatrix: LSGlobe.Matrix4.toArray(tileset.modelMatrix) //保存模型位置的矩阵
})
las/laz
bizType | fileType |
---|---|
4 | las |
4 | laz |
las/laz 属性类型
ts
export type lasAttributes = {
lon?: number // 经度
lat?: number // 纬度
height?: number // 海拔高度
granularity?: number // 精细度
modelMatrix?: number[] //模型矩阵
pointSize?: number // 点大小1~10
/**
* las着色模式
* 0: 真彩色
* 1: 强度色
* 2: 回波次数色
* 3: 高程彩色
* 4:分类设色
*/
lasTintMode?: (typeof lasRenderModes)[number]['value']
/**样式 */
style?: Record<string, any>
/**分类设色配置
* [[分类号,分类名,颜色],...]
*/
lasTintClassifications?: string[][]
}
/**las着色模式 */
export const lasRenderModes = [
{
label: '真彩色',
value: 0
},
{
label: '强度色',
value: 1
},
{
label: '回波次数色',
value: 2
},
{
label: '高程彩色',
value: 3
},
{
label: '分类着色',
value: 4
}
] as const
/**las额外属性 */
export type lasExtra = {
maxIntensity?: number
minIntensity?: number
Classification?: string
maxReturnNumber?: number
extrasVersion?: number
maxElevation?: number
minElevation?: number
realColor?: number //真彩色,没有真彩色则没有这个字段
}
/**las默认分类 */
export const las_default_classifications = [
['0', '未分类', '#FF8080'],
['1', '地面', '#804000'],
['2', '建筑物', '#FF8000'],
['3', '低植被', '#008000'],
['4', '中等植被', '#00C800'],
['5', '高植被', '#00FF00'],
['6', '水体', '#0000FF'],
['7', '道路', '#808080'],
['8', '车辆', '#FF00FF'],
['9', '行人', '#FF0080'],
['10', '铁路', '#808080'],
['11', '桥梁', '#AAAAAA'],
['12', '高压线', '#FFFF00'],
['13', '输电塔', '#00FFFF'],
['14', '其他', '#FF8080']
] as const
加载 las/laz
加载样式
加载样式使用方法
ts
init_las_style(tileset, attr)
ts
/**
* 初始化las样式
* @param tileset
* @param attr
*/
export function init_las_style<T extends lasAttributes>(tileset: any, attr: T) {
if (attr.modelMatrix) {
tileset.modelMatrix = LSGlobe.Matrix4.fromArray(attr.modelMatrix)
}
if (!attr.style) {
tileset.style = new LSGlobe.Cesium3DTileStyle(
gen_las_style(
tileset,
attr.pointSize,
attr.lasTintMode,
attr.lasTintClassifications
)
)
} else {
tileset.style = new LSGlobe.Cesium3DTileStyle(attr.style)
}
tileset.maximumScreenSpaceError = attr.granularity
}
/**生成las样式 */
export function gen_las_style(
tileset: any,
pointSize: number | undefined,
tintMode: lasProps['lasTintMode'],
classifications?: lasProps['lasTintClassifications']
) {
const colorStyle = get_las_tint_mode_color_style(
tileset.extras,
tintMode,
classifications
)
return {
pointSize: pointSize ?? 4,
...colorStyle
}
}
/**生成las着色模式样式 */
export function get_las_tint_mode_color_style(
lasTilesetExtras: lasExtra,
tintMode?: lasProps['lasTintMode'],
classifications?: lasProps['lasTintClassifications']
) {
if (isVoid(lasTilesetExtras) || isVoid(tintMode)) {
console.warn('未设置las渲染模式')
return {}
}
switch (tintMode) {
case 0:
return {}
case 1:
return createIntensityStyle()
case 2:
return createReturnNumberStyle()
case 3:
return createElevationStyle()
case 4:
return createClassificationStyle()
default:
return {}
}
/**强度色 */
function createIntensityStyle() {
const maxIntensity = lasTilesetExtras?.maxIntensity
const minIntensity = lasTilesetExtras?.minIntensity
if (isVoid(maxIntensity) || isVoid(minIntensity)) {
console.warn('未设置las强度范围')
return {}
}
const delta =
maxIntensity <= minIntensity ? 0.25 : (maxIntensity - minIntensity) / 4.0
return {
color: {
conditions: [
[`\${INTENSITY} >= ${maxIntensity}`, "color('rgba(255,0,0,1)')"], // 红色
[
`\${INTENSITY} >= ${maxIntensity - delta}`,
"color('rgba(255,255,0,1)')"
], // 黄色
[
`\${INTENSITY} >= ${maxIntensity - 2 * delta}`,
"color('rgba(0,255,0,1)')"
], // 绿色
[
`\${INTENSITY} >= ${maxIntensity - 3 * delta}`,
"color('rgba(0,255,255,1)')"
], // 青色
[
`\${INTENSITY} >= ${maxIntensity - 4 * delta}`,
"color('rgba(0,0,255,1)')"
],
['true', "color('rgba(0,0,255,1)')"] // 蓝色
]
}
}
}
/**回波次数色 */
function createReturnNumberStyle() {
const maxReturnNumber = lasTilesetExtras?.maxReturnNumber
if (isVoid(maxReturnNumber)) {
console.warn('未设置las回波次数')
return {}
}
if (maxReturnNumber > 2) {
const midValue = Math.ceil((maxReturnNumber + 1) / 2.0)
return {
color: {
conditions: [
[`\${ECHO} === ${maxReturnNumber}`, "color('rgba(255,0,0,1)')"], // 最大回波红色
[`\${ECHO} === ${midValue}`, "color('rgba(0,255,0,1)')"], // 中间回波绿色
[`\${ECHO} === 1`, "color('rgba(0,0,255,1)')"], // 最小回波蓝色
['true', "color('rgba(0,0,0,1)')"] // 最小回波黑色
]
}
}
} else if (maxReturnNumber === 2) {
return {
color: {
conditions: [
[`\${ECHO} === 2`, "color('rgba(0,255,0,1)')"], // 回波2绿色
[`\${ECHO} === 1`, "color('rgba(0,0,255,1)')"], // 最小回波蓝色
['true', "color('rgba(0,0,255,1)')"] // 回波1蓝色
]
}
}
} else {
return {
color: "color('rgba(0,0,255,1)')" // 单回波全部蓝色
}
}
}
/**分类着色 */
function createClassificationStyle() {
const classification = lasTilesetExtras?.Classification
if (isVoid(classification)) {
console.warn('未设置las分类')
return {}
}
if (classifications) {
return {
color: {
conditions: classifications.map((e) => [
`\${CLASSIFICATION} === ${e[0]}`,
`color('${e[2]}')`
])
}
}
} else {
return {}
}
}
// 新增颜色工具函数
function generateGradientColors(count: number): string[] {
const colors: string[] = []
for (let i = 0; i < count; i++) {
// HSL: 从蓝色(240)到红色(0)
const hue = (i * 240) / (count - 1)
colors.push(`rgba(${HSLToRGB(hue, 100, 50).join(',')},1)`)
}
return colors
}
function HSLToRGB(h: number, s: number, l: number): [number, number, number] {
s /= 100
l /= 100
const k = (n: number) => (n + h / 30) % 12
const a = s * Math.min(l, 1 - l)
const f = (n: number) =>
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))
return [
Math.round(255 * f(0)),
Math.round(255 * f(8)),
Math.round(255 * f(4))
]
}
//高程着色
function createElevationStyle() {
const maxElevation = lasTilesetExtras?.maxElevation
const minElevation = lasTilesetExtras?.minElevation
if (isVoid(maxElevation) || isVoid(minElevation)) {
console.warn('未设置las高程范围')
return {}
}
const SEGMENTS = 50 // 区间数量
const delta =
maxElevation <= minElevation
? 0.25
: (maxElevation - minElevation) / SEGMENTS
const colors = generateGradientColors(SEGMENTS + 1)
const conditions = []
for (let i = 0; i < SEGMENTS; i++) {
conditions.push([
`\${ELEVATION} >= ${maxElevation - i * delta}`,
`color('${colors[i]}')`
])
}
conditions.push(['true', `color('${colors[SEGMENTS]}')`])
return {
color: {
conditions
}
}
}
}
/**生成las默认分类 */
export function gen_default_classfications(lasTilesetExtras: lasExtra) {
const classification = lasTilesetExtras?.Classification
if (isVoid(classification)) {
console.warn('未设置las分类')
return undefined
}
const classificationsTypes = classification
.split(';')
.map((e) => Number(e.split(',')[0]))
return classificationsTypes.map((e) => [
e.toString(),
las_default_classifications[e]?.[1] ?? '其他',
las_default_classifications[e]?.[2] ?? '#FF8080'
])
}
/**获取可启用的着色模式 */
export function get_las_tint_mode_enable_arr(lasTilesetExtras?: lasExtra) {
const arr: number[] = []
if (isVoid(lasTilesetExtras)) {
return arr
}
const classification = lasTilesetExtras?.Classification
const maxReturnNumber = lasTilesetExtras?.maxReturnNumber
const maxIntensity = lasTilesetExtras?.maxIntensity
const minIntensity = lasTilesetExtras?.minIntensity
const realColor = lasTilesetExtras?.realColor
const maxElevation = lasTilesetExtras?.maxElevation
const minElevation = lasTilesetExtras?.minElevation
if (!isVoid(classification)) {
arr.push(4)
}
if (!isVoid(maxReturnNumber)) {
arr.push(2)
}
if (!isVoid(maxIntensity) && !isVoid(minIntensity)) {
arr.push(1)
}
if (!isVoid(realColor)) {
arr.push(0)
}
if (!isVoid(maxElevation) && !isVoid(minElevation)) {
arr.push(3)
}
return arr.sort((a, b) => a - b)
}
function isVoid(val: unknown) {
return val === undefined || val === null || val === ''
}
保存属性
ts
/**获取经纬高 */
const { lon, lat, height } = (() => {
const formModel = {
lon: 120,
lat: 30,
height: 0
}
viewer.boxEditBoxGeometry.viewModel.editObject = formModel.tileset
viewer.boxEditBoxGeometry.viewModel.move()
const pos = viewer!.boxEditBoxGeometry.viewModel.position
formModel.lon = pos.x
formModel.lat = pos.y
formModel.height = pos.z
viewer!.boxEditBoxGeometry.viewModel.editObject = null
return formModel
})()
saveAttr<lasAttributes>({
lon: lon,
lat: lat,
height: height,
granularity: 10,
pointSize: 4,
modelMatrix: LSGlobe.Matrix4.toArray(tileset.modelMatrix), //保存模型位置的矩阵
lasTintMode: 1,
style: gen_las_style(
formModel.tileset,
formModel.pointSize,
formModel.lasTintMode,
formModel.lasTintClassifications
),
lasTintClassifications: gen_default_classfications(formModel.tileset.extras)
})
BIM
bizType |
---|
5 |
BIM 属性类型
ts
type bimAttributes = {
lon?: number // 经度
lat?: number // 纬度
height?: number // 海拔高度
modelMatrix?: number[] //模型矩阵
opacity?: number // 不透明度
granularity?: number // 精细度
hasProjection?: boolean // 是否有投影
}
加载 BIM
加载样式
ts
init_bim_style(tileset, attr, hasProjection)
ts
function init_bim_style<T extends bimAttributes>(
tileset: any,
attr: T,
hasProjection: boolean
) {
//没有投影的时候才设置模型矩阵
if (attr.modelMatrix && hasProjection === false) {
tileset.modelMatrix = LSGlobe.Matrix4.fromArray(attr.modelMatrix)
}
tileset.style = new LSGlobe.Cesium3DTileStyle({
color: "color('rgba(255,255,255," + (attr.opacity ?? 100) / 100 + ")')"
})
tileset.maximumScreenSpaceError = attr.granularity
}
/**判断BIM是否有投影[ hasProjection ]*/
async function is_bim_has_projection(folderId: string) {
const res = await getLastPublishConfig(folderId)
if (!res?.data?.cfgValue) {
return false
}
try {
const val = JSON.parse(decodeURIComponent(res.data.cfgValue))
console.log('bim PROJ CFG', val)
if (
val?.['SHOW_PRJ'] === false ||
val?.['hasProjection'] === false ||
!val
) {
return false
} else {
return true
}
} catch (error) {
console.error(error)
}
return false
}
function getLastPublishConfig(folderId: string) {
return request({
url: '/admin/tx/data/getLastDataConfig',
method: 'get',
params: {
folderId
}
})
}
保存属性
ts
/**获取经纬高 */
const { lon, lat, height } = (() => {
const formModel = {
lon: 120,
lat: 30,
height: 0
}
viewer.boxEditBoxGeometry.viewModel.editObject = formModel.tileset
viewer.boxEditBoxGeometry.viewModel.move()
const pos = viewer!.boxEditBoxGeometry.viewModel.position
formModel.lon = pos.x
formModel.lat = pos.y
formModel.height = pos.z
viewer!.boxEditBoxGeometry.viewModel.editObject = null
return formModel
})()
saveAttr<bimAttributes>({
lon: lon,
lat: lat,
height: height,
opacity: 100,
granularity: 10,
hasProjection: true,
modelMatrix: LSGlobe.Matrix4.toArray(tileset.modelMatrix) //保存模型位置的矩阵
})
shp
bizType | fileType |
---|---|
6 | shp |
shp 属性类型
ts
type shpAttributes = {
attachType?: number //依附模式
styles?: {
styles: Record<string, any>[]
} //样式
selectedStyles?: {
styles: Record<string, any>[]
} //选中的样式
}
加载 shp
加载 shp 需要的参数
ts
/**
* 加载shp
* @param id 数据id
* @param jsonPath shpjson路径
*/
async function loadShp({ id, jsonPath }: { id: string; jsonPath: string }) {
try {
const currentImageLayer = await (LSGlobe as any).VectorTileProvider.fromUrl(
jsonPath,
{ viewer: viewer, maximumLevel: 30 }
)
const shptype = await fnGetShpAttributeByMaterilId(currentImageLayer, id)
const imageryLayer = viewer!.imageryLayers.addImageryProvider(
currentImageLayer,
3
)
var rect = currentImageLayer._rectangle
const flyFn = () =>
viewer!.camera.flyTo({
destination: rect
})
flyFn()
return { imageryLayer, shptype }
} catch (error) {
console.error(`Error loading vector tiles: ${error}`)
}
return null
async function fnGetShpAttributeByMaterilId(
imageryprovider: any,
materialid: any
) {
const oStyle = {
styletyle: 'default',
color: 'rgba(33, 150, 243,0.3)',
lineType: (LSGlobe as any).VectorTileLineType.SOLID,
lineWidth: 1,
outline: true,
outlineColor: '#2196F3',
icon: '/scene/images/GEMarker/red-circle.png',
textField: 'NAME',
font: "normal 16px 'Microsoft YaHei'"
}
const oSelectedStyle = {
color: 'rgba(255, 87, 34,0.1)',
lineType: (LSGlobe as any).VectorTileLineType.SOLID,
lineWidth: 1,
outline: true,
outlineColor: '#FF5722',
icon: '/scene/images/GEMarker/red-circle.png',
textField: 'NAME',
font: "normal 16px 'Microsoft YaHei'"
}
try {
const res = await getShpAttrByFolderId(materialid)
if (res.code == 0) {
if (!res.data) {
console.warn('获取shp素材的属性为空')
return 1
}
var sGeometrytype = res.data.geometryType
var oStylePortion = { ...oStyle } as any
var oSelectedStylePortion = { ...oSelectedStyle } as any
if (sGeometrytype.indexOf('POINT') >= 0) {
oStylePortion.color = 'rgba(255, 255, 255,1)'
oStylePortion.outlineColor = '#000000'
oStylePortion.outline = true
oStylePortion.lineWidth = 3
oStylePortion.font = 'normal 16px 微软雅黑'
oStylePortion.textColor = '#FFFFFF'
oStylePortion.textField = undefined
oStylePortion.textOutlineColor = '#000000'
oSelectedStylePortion.lineWidth = 3
oSelectedStylePortion.color = 'rgba(255, 0, 0,1)'
oSelectedStylePortion.outlineColor = '#000000'
} else if (sGeometrytype.indexOf('LINESTRING') >= 0) {
oStylePortion.lineWidth = 4
oSelectedStylePortion.lineWidth = 4
oStylePortion.color = 'rgba(251,188,4,1)'
oSelectedStylePortion.color = 'rgba(255, 87, 34,1)'
delete oStylePortion.icon
delete oStylePortion.textField
delete oSelectedStylePortion.icon
delete oSelectedStylePortion.textField
} else if (sGeometrytype.indexOf('POLYGON') >= 0) {
delete oStylePortion.icon
delete oStylePortion.textField
delete oSelectedStylePortion.icon
delete oSelectedStylePortion.textField
}
var styles = new (LSGlobe as any).VectorTileStyleCollection([
new (LSGlobe as any).VectorTileStyle(oStylePortion)
])
var selectedstyles = new (LSGlobe as any).VectorTileStyleCollection([
new (LSGlobe as any).VectorTileStyle(oSelectedStylePortion)
])
imageryprovider.styles = styles
imageryprovider.selectedStyles = selectedstyles
return getShpType(sGeometrytype)
} else {
console.error('查询不到该大矢量数据信息')
}
} catch (err) {
console.log(err)
}
return 1
}
function getShpType(sGeometrytype: string) {
if (sGeometrytype.indexOf('POINT') >= 0) {
return 1
} else if (sGeometrytype.indexOf('LINESTRING') >= 0) {
return 2
} else if (sGeometrytype.indexOf('POLYGON') >= 0) {
return 3
}
return 1
}
function getShpAttrByFolderId(folderId: string) {
return request({
url: '/admin/tx/shp/getAttributeByFolderId',
method: 'get',
params: {
folderId
}
})
}
}
加载样式
加载样式使用方法
ts
function init_shp_style(oImagery: any, styles?: any[], selectedStyles?: any[]) {
if (styles) {
oImagery.imageryProvider.styles = new (
LSGlobe as any
).VectorTileStyleCollection(
cloneDeep(styles).map((s) => {
return new (LSGlobe as any).VectorTileStyle(s)
})
)
}
if (selectedStyles) {
oImagery.imageryProvider.selectedStyles = new (
LSGlobe as any
).VectorTileStyleCollection(
cloneDeep(selectedStyles).map((s) => {
return new (LSGlobe as any).VectorTileStyle(s)
})
)
}
}
style 书写规则
点要素样式(shptype=1)
属性 | 全局模式 | 分类模式 | 值类型 | 说明 |
---|---|---|---|---|
textColor | ✓ | ✓ | string | 文字颜色-rgba 字符串 |
font | ✓ | ✓ | string | normal 16px 'Microsoft YaHei' 类似 css 的 Font |
outline | ✓ | ✓ | boolean | true |
outlineColor | ✓ | ✓ | string | 边线颜色-rgba 字符串 |
textOutlineColor | ✓ | ✓ | string | 边线颜色-rgba 字符串 |
lineWidth | ✓ | ✓ | number | 边线宽度 |
textField | ✓ | ✓ | string | 显示文字的字段 |
icon | ✓ | ✓ | string | 图标 url |
classificationField | × | ✓ | string | 分类的字段 |
classificationFieldValue | × | ✓ | string | 分类的值 |
线要素样式(shptype=2)
属性 | 全局模式 | 分类模式 | 值类型 | 说明 |
---|---|---|---|---|
color | ✓ | ✓ | string | 边线颜色-rgba 字符串 |
lineType | ✓ | ✓ | string/string[] | 0,[2,2],[6,2] |
outline | ✓ | ✓ | boolean | 是否有边线 |
lineWidth | ✓ | ✓ | number | 边线宽度 |
textField | ✓ | ✓ | undefined | undefined |
classificationField | × | ✓ | string | 分类的字段 |
classificationFieldValue | × | ✓ | string | 分类的值 |
面要素样式(shptype=3)
属性 | 全局模式 | 分类模式 | 值类型 | 说明 |
---|---|---|---|---|
color | ✓ | ✓ | string | 面颜色 rgba 字符串 |
lineType | ✓ | ✓ | string/string[] | 0,[2,2],[6,2] |
lineWidth | ✓ | ✓ | number | 边线宽度 |
outline | ✓ | ✓ | boolean | 是否有边线 |
outlineColor | ✓ | ✓ | string | 边线颜色-rgba 字符串 |
textField | ✓ | ✓ | undefined | undefined |
classificationField | × | ✓ | string | 分类的字段 |
classificationFieldValue | × | ✓ | string | 分类的值 |
样式解释
全局模式:全局模式下的属性会应用到所有要素上
json
[
{
"color": "RGBA(251, 188, 4, 1)",
"lineWidth": 4,
"lineType": 0,
"outline": true,
"outlineColor": "#000000"
}
]
分类模式:分类模式下的属性会根据分类的字段和值来应用到对应的要素上
json
[
{
"outline": true,
"lineWidth": 3,
"outlineColor": "#000000",
"icon": "/scene/images/GEMarker/red-circle.png",
"textField": "ADDRESS",
"textColor": "RGBA(145, 220, 203, 1)",
"textOutlineColor": "#000000",
"font": "normal 16px 'Microsoft YaHei'",
"classificationField": "ZHONGLEI",
"classificationFieldValue": "7301"
},
{
"outline": true,
"lineWidth": 3,
"outlineColor": "#000000",
"icon": "/scene/images/GEMarker/red-circle.png",
"textField": "ADDRESS",
"textColor": "RGBA(140, 32, 106, 1)",
"textOutlineColor": "#000000",
"font": "normal 16px 'Microsoft YaHei'",
"classificationField": "ZHONGLEI",
"classificationFieldValue": "7304"
},
{
"color": "#FFFFFF",
"lineWidth": 3,
"lineType": [],
"outline": true,
"outlineColor": "#000000",
"icon": "/scene/images/GEMarker/red-circle.png",
"textField": "ADDRESS",
"textColor": "RGBA(255, 255, 255, 1)",
"textOutlineColor": "#000000",
"font": "normal 16px 'Microsoft YaHei'"
}
]
classificationField/classificationFieldValue 获取
ts
//例子
const classificationField = await fnGetFields(id)
const classificationFieldValues = await queryShpGeometryType({
columnName: fields[0],
folderId: id
})
/**获取shp某个字段的值 */
function queryShpGeometryType(data: {
columnName?: string
folderId?: string
}) {
return request({
url: '/admin/tx/shp/queryShpGeometryType',
method: 'get',
params: data
})
}
/**获取shp所有字段 */
async function fnGetFields(id: string) {
try {
const result = await getDataIndex({ dataId: id })
let oFieldList = result['vector_layers'][0]['fields']
let not_allowed_attr = [
'layer',
'clustered',
'clustered',
'sqrt_point_count',
'point_count',
'tx_center_x',
'tx_center_y'
]
not_allowed_attr.forEach((item) => {
delete oFieldList[item]
})
return Object.keys(oFieldList)
} catch (err) {
console.log(err)
}
function getDataIndex(params: { dataId: string }) {
const token = CONSTANTS.TOKEN
return request({
url: `/admin/tx/preview/data/index/${params.dataId}`,
method: 'get',
params: {
token
}
})
}
}
ts
/**
* 设置shp的样式
* @param oImagery
* @param aStyle 样式数组,来自上表
*/
function fnImagerySetStyles(oImagery: any, aStyle: any) {
var aStylesPotion = []
for (var i = 0; i < aStyle.length; i++) {
aStylesPotion.push(new (LSGlobe as any).VectorTileStyle(aStyle[i]))
}
var styles = new (LSGlobe as any).VectorTileStyleCollection(aStylesPotion)
oImagery.imageryProvider.styles = styles
}
保存属性
ts
const styles = oImagery.imageryProvider.styles.toJson()
const selectedStyles = oImagery.imageryProvider.selectedStyles.toJson()
saveAttr<shpAttributes>({
attachType: attachType.value,
styles,
selectedStyles
})
kml/kmz
bizType | fileType |
---|---|
6 | kml |
6 | kmz |
加载 kml
ts
/**
* 加载kml/kmz
* @param jsonPath kml/kmz路径
*/
async function load_kml_kmz(jsonPath: string) {
try {
const dataSource = await LSGlobe.KmlDataSource.load(jsonPath, {
camera: viewer!.scene.camera,
canvas: viewer!.scene.canvas
})
viewer!.dataSources.add(dataSource)
const flyFn = () => viewer!.flyTo(dataSource)
flyFn()
//关闭地形深度,需要在加载别的素材的时候打开
viewer!.scene.globe.depthTestAgainstTerrain = false
} catch (error) {
console.error(`Error loading tileset: ${error}`)
}
}
属性类型
无
加载样式
无
保存属性
保存属性使用方法/类型
ts
saveAttr({})
cad/lcad
bizType | fileType |
---|---|
6 | dwg |
6 | lcad |
6 | dxf |
cad/lcad 属性类型
ts
type cadAttributes = {
attachType?: number //1:依模型 0:依地表
opacity?: number //不透明度
}
加载 cad/lcad
ts
/**
* 加载cad/lcad
* @param jsonPath
*/
async function loadCad(jsonPath: string) {
const { imageryLayers } = viewer!
try {
const imageryProvider = await (LSGlobe as any).LSImageryProvider.fromUrl(
jsonPath
)
const imageryLayer = imageryLayers.addImageryProvider(imageryProvider)
const flyFn = () =>
viewer!.camera.flyTo({
destination: imageryProvider.rectangle
})
flyFn()
return { imageryLayer }
} catch (error) {
console.error(`Error loading tileset: ${error}`)
}
return { imageryLayer: null }
}
加载样式
加载样式使用方法
ts
function init_cad_style<T extends cadAttributes>(imageryLayer: any, attr: T) {
imageryLayer.alpha = (attr.opacity ?? 100) / 100
}
保存属性
ts
saveAttr<cadAttributes>({
attachType: 1,
opacity: 100
})
gltf/glb
bizType | fileType |
---|---|
8 | gltf |
8 | glb |
gltf/glb 属性类型
ts
type glbAttributes = {
lon?: number // 经度
lat?: number // 纬度
height?: number // 海拔高度
modelMatrix?: number[] //模型矩阵
rotateZ?: number // 旋转角度
length?: number // 长
width?: number // 宽
modelHeight?: number // 高
scale?: number // 缩放0~Infinity,默认1
}
加载 gltf/glb
加载 gltf/glb 需要的参数
ts
/**
* 加载glb/gltf
* @param jsonPath glb/gltf路径
* @param position
*/
async function loadGlbGltf({
jsonPath,
position
}: {
jsonPath: string
position: string
}) {
const positionArr = (position?.split(',')?.map((e) => Number(e) ?? 0) ?? [
120, 30, 0
]) as [number, number, number]
const origin = LSGlobe.Cartesian3.fromDegrees(...positionArr)
const heading = LSGlobe.Math.toRadians(0.0)
const pitch = LSGlobe.Math.toRadians(0.0)
const roll = LSGlobe.Math.toRadians(0.0)
const hpr = new LSGlobe.HeadingPitchRoll(heading, pitch, roll)
const modelMatrix = LSGlobe.Transforms.headingPitchRollToFixedFrame(
origin,
hpr
)
const loader = () => {
return new Promise<{
model: any
positionArr: [number, number, number]
modelMatrix: number[]
}>(async (resolve, reject) => {
try {
const gltf = await (LSGlobe.Model as any).fromGltfAsync({
url: jsonPath,
modelMatrix
})
const model = viewer!.scene.primitives.add(gltf)
model.readyEvent.addEventListener(async () => {
model.activeAnimations.addAll({
loop: LSGlobe.ModelAnimationLoop.REPEAT,
multiplier: 1
})
resolve({
model,
positionArr,
modelMatrix: LSGlobe.Matrix4.toArray(modelMatrix)
})
})
} catch (error) {
reject(error)
}
})
}
try {
const res = await loader()
return res
} catch (error) {
console.error('loadGlbGltf error:', error)
}
return { model: null, positionArr: null, modelMatrix: null }
}
加载样式
加载样式使用方法
ts
function init_glb_style<
T extends {
modelMatrix?: number[]
scale?: number
}
>(model: any, attr: T) {
const { modelMatrix } = attr
if (!modelMatrix) return
model.modelMatrix = LSGlobe.Matrix4.fromArray(modelMatrix)
if (attr.scale !== undefined || attr.scale !== null) {
model.scale = attr.scale
}
}
保存属性
ts
/**获取经纬高 */
const { lon, lat, height } = (() => {
const formModel = {
lon: 120,
lat: 30,
height: 0
}
viewer.boxEditBoxGeometry.viewModel.editObject = formModel.tileset
viewer.boxEditBoxGeometry.viewModel.move()
const pos = viewer!.boxEditBoxGeometry.viewModel.position
formModel.lon = pos.x
formModel.lat = pos.y
formModel.height = pos.z
viewer!.boxEditBoxGeometry.viewModel.editObject = null
return formModel
})()
/**更新旋转 */
function updateRotateZ(rotateZ: number) {
viewer!.boxEditBoxGeometry.viewModel.editObject = model
viewer!.boxEditBoxGeometry.viewModel.rotation = new LSGlobe.Cartesian3(
0,
0,
rotateZ
)
viewer!.boxEditBoxGeometry.viewModel.editObject = null
}
function getModelBoundingSize(model: any) {
if (!model) return 1
try {
// 获取模型包围球
const boundingSphere = model.boundingSphere
if (!boundingSphere) return 1
// 返回包围球半径作为默认尺寸
return boundingSphere.radius || 1
} catch (error) {
console.warn('获取模型默认尺寸失败:', error)
return 1
}
}
const size = getModelBoundingSize(model)
saveAttr<glbAttributes>({
lon: lon,
lat: lat,
height: height,
modelMatrix: LSGlobe.Matrix4.toArray(model.modelMatrix),
rotateZ: 0,
length: size,
width: size,
modelHeight: size,
scale: model.scale
})