Files
sdk4.0/src/Obj/Base/LabelObject/index.js

595 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 标注
*/
import Base from '../index'
import MouseEvent from '../../../Event/index'
import {
getGroundCover
} from '../../../Global/global'
import { getFontFamily } from '../../Element/fontSelect'
import {
addCluster,
remove_entity_from_cluster
} from '../../../Global/cluster/cluster'
class LabelObject extends Base {
#updateBillboardImageTimeout
constructor(sdk, options = {}, model) {
super(sdk, options)
this.model = model
this.options.near = options.near || options.near === 0 ? options.near : 2000
this.options.far = options.far || options.far === 0 ? options.far : 100000
this.options.scaleByDistance = options.scaleByDistance || false
this.options.show =
options.show || options.show === false ? options.show : true
this.options.text = options.text
let textArray = this.options.text.split('\n')
for (let i = 0; i < textArray.length; i++) {
if (textArray[i].length > 40) {
textArray[i] = textArray[i].slice(0, 40 - textArray[i].length)
}
}
if (textArray.length > 10) {
textArray.splice(10 - textArray.length)
}
this.options.text = textArray.join('\n')
this.options.fontFamily = options.fontFamily || 0
this.font = getFontFamily(this.options.fontFamily) || 'SimHei'
this.options.fontSize = options.fontSize || 20
this.options.lineWidth = options.lineWidth || 4
this.options.lineColor = options.lineColor || '#00ffff80'
this.options.color = options.color || '#ffffff'
this.options.ground =
options.ground || options.ground === false ? options.ground : true
this.options.pixelOffset =
options.pixelOffset || options.pixelOffset === 0
? options.pixelOffset
: 20
this.options.backgroundColor = options.backgroundColor || [
'#00ffff80',
'#00ffff80'
]
this.event = new MouseEvent(this.sdk)
this.entity
this.create(this.options.position)
this.picking = true
}
async create() {
let _this = this
if (!this.options.position[2] && this.options.position[2] !== 0) {
this.options.position[2] = await this.getClampToHeight({
lng: this.options.position[0],
lat: this.options.position[1]
})
}
this.originalOptions = copyObj(this.options)
let id = this.options.id + '-label'
let oldEntity = this.sdk.viewer.entities.getById(id)
if(oldEntity) {
this.sdk.viewer.entities.remove(oldEntity)
}
this.entity = this.sdk.viewer.entities.add({
show: this.options.show,
id: this.options.id + '-label',
position: new Cesium.CallbackProperty(function () {
if (_this.model) {
// return Cesium.Cartesian3.fromDegrees(_this.options.position[0], _this.options.position[1], _this.model.originalBoundingSphereRadius*2*_this.model.customScale.z + _this.options.position[2])
if (_this.model.isMove) {
let scale = _this.model.customScale.x
if (_this.model.customScale.y > scale) {
scale = _this.model.customScale.y
}
if (_this.model.customScale.z > scale) {
scale = _this.model.customScale.z
}
let point1 = Cesium.Cartesian3.fromDegrees(
_this.options.position[0],
_this.options.position[1],
_this.options.position[2] +
(_this.model.originalBoundingSphereRadius || 1) *
2 *
(scale || 0.01)
)
// 点2的位置也使用经纬高表示
let point2 = Cesium.Cartesian3.fromDegrees(
_this.options.position[0],
_this.options.position[1],
_this.options.position[2] -
(_this.model.originalBoundingSphereRadius || 1) *
2 *
(scale || 0.01)
)
let direction = Cesium.Cartesian3.subtract(
point2,
point1,
new Cesium.Cartesian3()
)
let c = Cesium.Cartesian3.normalize(direction, direction)
let ray = new Cesium.Ray(point1, c)
let pickedObjects = _this.viewer.scene.drillPickFromRay(ray, 5)
for (let i = 0; i < pickedObjects.length; i++) {
if (
pickedObjects[i].object &&
pickedObjects[i].object.id &&
pickedObjects[i].object.id === _this.model.id
) {
let pos84 = _this.cartesian3Towgs84(pickedObjects[i].position, _this.sdk.viewer)
_this.options.position[0] = pos84.lng
_this.options.position[1] = pos84.lat
_this.options.position[2] = pos84.alt
break
}
}
}
return Cesium.Cartesian3.fromDegrees(
_this.options.position[0],
_this.options.position[1],
_this.options.position[2]
)
} else {
return Cesium.Cartesian3.fromDegrees(..._this.options.position)
}
}, false),
billboard: {
image: this.getcanvas(),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: new Cesium.CallbackProperty(function () {
return getGroundCover() ? undefined : Number.POSITIVE_INFINITY
}, false),
scaleByDistance: this.options.scaleByDistance
? new Cesium.NearFarScalar(this.options.near, 1, this.options.far, 0)
: undefined,
pixelOffsetScaleByDistance: this.options.scaleByDistance
? new Cesium.NearFarScalar(this.options.near, 1, this.options.far, 0)
: undefined
}
// label: {
// show: this.options.show,
// text: new Cesium.CallbackProperty(function () {
// return _this.options.text
// }, false),
// font: this.options.fontSize + "px Helvetica",
// fillColor: Cesium.Color.fromCssColorString(this.options.color),
// pixelOffset: new Cesium.Cartesian2(0, -this.options.pixelOffset),
// outlineColor: Cesium.Color.BLACK,
// backgroundColor: Cesium.Color.fromCssColorString('#42c6ef'),
// backgroundPadding: new Cesium.Cartesian2(12, 12),
// showBackground: true,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// outlineWidth: 1,
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// },
})
}
get position() {
return this.options.position
}
set position(v) {
// console.log(v)
this.options.position = v
if (!v[2] && v[2] !== 0) {
let objectsToExclude = [...this.sdk.viewer.entities.values]
this.getClampToHeight({
lng: v[0],
lat: v[1]
}, objectsToExclude).then(height => {
v[2] = height
this.options.position = [...v]
})
// let point1 = Cesium.Cartesian3.fromDegrees(this.options.position[0], this.options.position[1], 0);
// let point2 = Cesium.Cartesian3.fromDegrees(this.options.position[0], this.options.position[1], 10000000);
// let direction = Cesium.Cartesian3.subtract(point2, point1, new Cesium.Cartesian3());
// let c = Cesium.Cartesian3.normalize(direction, direction);
// let ray = new Cesium.Ray(point1, c);
// let r = {}
// let pickedObjects = this.sdk.viewer.scene.drillPickFromRay(ray);
// for (let i = 0; i < pickedObjects.length; i++) {
// if (pickedObjects[i].position) {
// r = pickedObjects[i]
// break
// }
// }
// if (r && r.position) {
// this.options.position[2] = this.cartesian3Towgs84(r.position, this.sdk.viewer).alt
// }
// else {
// try {
// let promise = Cesium.sampleTerrainMostDetailed(this.sdk.viewer.terrainProvider, [Cesium.Cartographic.fromDegrees(this.options.position[0], this.options.position[1])]);
// promise.then((p) => {
// this.options.position[2] = p[0].height
// }).catch((e)=>{
// })
// } catch (error) {
// }
// }
} else {
this.options.position = [...v]
}
}
get show() {
return this.options.show
}
set show(v) {
this.options.show = v
if (!this.entity) {
return
}
this.entity.show = v
if (this.model) {
// return Cesium.Cartesian3.fromDegrees(this.options.position[0], this.options.position[1], this.model.originalBoundingSphereRadius*2*this.model.customScale.z + this.options.position[2])
let scale = this.model.customScale.x
if (this.model.customScale.y > scale) {
scale = this.model.customScale.y
}
if (this.model.customScale.z > scale) {
scale = this.model.customScale.z
}
let point1 = Cesium.Cartesian3.fromDegrees(
this.options.position[0],
this.options.position[1],
this.options.position[2] +
(this.model.originalBoundingSphereRadius || 1) *
2 *
(scale || 0.01)
)
// 点2的位置也使用经纬高表示
let point2 = Cesium.Cartesian3.fromDegrees(
this.options.position[0],
this.options.position[1],
this.options.position[2] -
(this.model.originalBoundingSphereRadius || 1) *
2 *
(scale || 0.01)
)
let direction = Cesium.Cartesian3.subtract(
point2,
point1,
new Cesium.Cartesian3()
)
let c = Cesium.Cartesian3.normalize(direction, direction)
let ray = new Cesium.Ray(point1, c)
let pickedObjects = this.viewer.scene.drillPickFromRay(ray, 5)
for (let i = 0; i < pickedObjects.length; i++) {
if (
pickedObjects[i].object &&
pickedObjects[i].object.id &&
pickedObjects[i].object.id === this.model.id
) {
let pos84 = this.cartesian3Towgs84(pickedObjects[i].position, this.sdk.viewer)
this.options.position[0] = pos84.lng
this.options.position[1] = pos84.lat
this.options.position[2] = pos84.alt
break
}
}
}
else if (this.options.ground) {
let objectsToExclude = [...this.sdk.viewer.entities.values]
this.getClampToHeight({
lng: this.options.position[0],
lat: this.options.position[1]
}, objectsToExclude).then(height => {
this.options.position[2] = height
})
}
}
get text() {
return this.options.text
}
set text(v) {
this.options.text = v
let textArray = this.options.text.split('\n')
for (let i = 0; i < textArray.length; i++) {
if (textArray[i].length > 40) {
textArray[i] = textArray[i].slice(0, 40 - textArray[i].length)
}
}
if (textArray.length > 10) {
textArray.splice(10 - textArray.length)
}
this.options.text = textArray.join('\n')
this.entity && (this.updateBillboardImage())
}
get color() {
return this.options.color
}
set color(v) {
this.options.color = v
this.entity && (this.entity.billboard.image = this.getcanvas())
}
get scaleByDistance() {
return this.options.scaleByDistance
}
set scaleByDistance(v) {
this.options.scaleByDistance = v
if (!this.entity) {
return
}
if (this.options.scaleByDistance) {
this.entity.billboard.scaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
this.entity.billboard.pixelOffsetScaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
} else {
this.entity.billboard.scaleByDistance = undefined
this.entity.billboard.pixelOffsetScaleByDistance = undefined
}
}
get near() {
return this.options.near
}
set near(v) {
let near = v
if (near > this.far) {
near = this.far
}
this.options.near = near
if (!this.entity) {
return
}
if (this.options.scaleByDistance) {
this.entity.billboard.scaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
this.entity.billboard.pixelOffsetScaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
} else {
this.entity.billboard.scaleByDistance = undefined
this.entity.billboard.pixelOffsetScaleByDistance = undefined
}
}
get far() {
return this.options.far
}
set far(v) {
let far = v
if (far < this.near) {
far = this.near
}
this.options.far = far
if (!this.entity) {
return
}
if (this.options.scaleByDistance) {
this.entity.billboard.scaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
this.entity.billboard.pixelOffsetScaleByDistance = new Cesium.NearFarScalar(
this.options.near,
1,
this.options.far,
0
)
} else {
this.entity.billboard.scaleByDistance = undefined
this.entity.billboard.pixelOffsetScaleByDistance = undefined
}
}
get fontSize() {
return this.options.fontSize
}
set fontSize(v) {
this.options.fontSize = Number(v)
if (!this.entity) {
return
}
this.updateBillboardImage()
}
get fontFamily() {
return this.options.fontFamily
}
set fontFamily(v) {
this.options.fontFamily = v || 0
this.font = getFontFamily(this.options.fontFamily) || 'SimHei'
this.updateBillboardImage()
}
get lineWidth() {
return this.options.lineWidth
}
set lineWidth(v) {
this.options.lineWidth = ((Number(v) || Number(v) === 0) ? Number(v) : 4)
if (!this.entity) {
return
}
this.updateBillboardImage()
}
get pixelOffset() {
return this.options.pixelOffset
}
set pixelOffset(v) {
this.options.pixelOffset = Number(v)
if (!this.entity) {
return
}
this.updateBillboardImage()
}
updateBillboardImage() {
clearTimeout(this.#updateBillboardImageTimeout)
this.#updateBillboardImageTimeout = setTimeout(() => {
clearTimeout(this.#updateBillboardImageTimeout)
this.entity && (this.entity.billboard.image = this.getcanvas())
}, 500)
}
get lineColor() {
return this.options.pixelOffset
}
set lineColor(v) {
this.options.lineColor = v || '#00ffff80'
if (!this.entity) {
return
}
this.entity.billboard.image = this.getcanvas()
}
get backgroundColor() {
return this.options.backgroundColor
}
set backgroundColor(v) {
this.options.backgroundColor = v
if (!this.entity) {
return
}
this.entity.billboard.image = this.getcanvas()
}
get ground() {
return this.options.ground
}
set ground(v) {
this.options.ground = v
}
// get backgroundColorStart() {
// return this.options.backgroundColor[0]
// }
// set backgroundColorStart(v) {
// this.options.backgroundColor[0] = v
// this.entity.billboard.image = this.getcanvas()
// }
// get backgroundColorEnd() {
// return this.options.backgroundColor[1]
// }
// set backgroundColorEnd(v) {
// this.options.backgroundColor[1] = v
// this.entity.billboard.image = this.getcanvas()
// }
getcanvas() {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
ctx.font = this.options.fontSize + 'px ' + this.font
let texts = this.options.text.split('\n')
let canvasWidth = 0
let canvasHeight = 0
for (let i = 0; i < texts.length; i++) {
const text = texts[i]
const width = ctx.measureText(text).width
if (width > canvasWidth) {
canvasWidth = width
}
canvasHeight += this.options.fontSize
}
canvasHeight = canvasHeight + 20 + (texts.length - 1) * 5
canvasWidth = canvasWidth + 30
if (canvasWidth < this.options.lineWidth) {
canvasWidth = this.options.lineWidth
}
canvas.width = canvasWidth
canvas.height = this.options.pixelOffset + canvasHeight
const linearGradient = ctx.createLinearGradient(
0,
0,
canvasWidth,
canvasHeight + 20
)
linearGradient.addColorStop(0, this.options.backgroundColor[0])
linearGradient.addColorStop(1, this.options.backgroundColor[1])
ctx.fillStyle = linearGradient
ctx.fillRect(0, 0, canvasWidth, canvasHeight)
ctx.fillStyle = this.options.color
ctx.font = this.options.fontSize + 'px ' + this.font
let maxWidth = 0
for (let i = 0; i < texts.length; i++) {
let width = ctx.measureText(texts[i]).width
if (maxWidth < width) {
maxWidth = width
}
}
maxWidth = maxWidth + 30
let centerDistance = (canvasWidth - maxWidth) / 2
for (let i = 0; i < texts.length; i++) {
const text = texts[i]
if (this.options.fontSize < 10) {
ctx.fillText(text, 15 + centerDistance, this.options.fontSize * (i + 1) + 10 + i * 5)
} else {
ctx.fillText(
text,
15 + centerDistance,
this.options.fontSize * (i + 1) +
(10 * 10) / this.options.fontSize +
i * 5
)
}
}
// 虚线
ctx.strokeStyle = this.options.lineColor
ctx.setLineDash([4, 4]) //设置虚线长度4间隔为4
ctx.lineWidth = this.options.lineWidth
ctx.beginPath()
ctx.moveTo(canvasWidth / 2, canvasHeight)
ctx.lineTo(canvasWidth / 2, canvasHeight + this.options.pixelOffset)
ctx.stroke()
ctx.closePath()
const canvas2 = document.createElement('canvas')
const ctx2 = canvas2.getContext('2d')
canvas2.width = canvas.width + 10
canvas2.height = canvas.height + 10
ctx2.drawImage(canvas, 5, 5);
// const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// ctx.putImageData(imageData, 40, 40);
return canvas2
}
remove() {
this.sdk.viewer.entities.remove(this.entity)
this.entity = null
}
flicker() { }
}
export default LabelObject
const copyObj = (obj = {}) => {
//变量先置空
let newobj = null
//判断是否需要继续进行递归
if (typeof obj == 'object' && obj !== null) {
newobj = obj instanceof Array ? [] : {} //进行下一层递归克隆
for (var i in obj) {
newobj[i] = copyObj(obj[i])
} //如果不是对象直接赋值
} else newobj = obj
return newobj
}