/** * 标注 */ 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 { constructor(sdk, options = {}, model) { super(sdk, options) this.model = model this._canvas = document.createElement('canvas') this._canvas2 = document.createElement('canvas') 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 }