595 lines
18 KiB
JavaScript
595 lines
18 KiB
JavaScript
/**
|
||
* 标注
|
||
*/
|
||
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
|
||
#canvas = document.createElement('canvas')
|
||
#canvas2 = document.createElement('canvas')
|
||
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() {
|
||
this.entity.billboard.image = this.getcanvas()
|
||
// clearTimeout(this.#updateBillboardImageTimeout)
|
||
// this.#updateBillboardImageTimeout = setTimeout(() => {
|
||
// clearTimeout(this.#updateBillboardImageTimeout)
|
||
// 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 ctx = this.#canvas.getContext('2d')
|
||
ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height);
|
||
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
|
||
}
|
||
this.#canvas.width = canvasWidth
|
||
this.#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 ctx2 = this.#canvas2.getContext('2d')
|
||
this.#canvas2.width = this.#canvas.width + 10
|
||
this.#canvas2.height = this.#canvas.height + 10
|
||
ctx2.drawImage(this.#canvas, 5, 5);
|
||
|
||
// const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||
// ctx.putImageData(imageData, 40, 40);
|
||
return this.#canvas2.toDataURL("image/png")
|
||
}
|
||
|
||
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
|
||
}
|