Files
sdk4.0/src/Obj/Base/TextObject/GroundText/index2.js
2025-07-16 15:02:18 +08:00

487 lines
16 KiB
JavaScript

import Dialog from '../../../Element/Dialog'
import EventBinding from '../../../Element/Dialog/eventBinding'
import { html, css } from './_element'
import Base from '../../index'
import MouseEvent from '../../../../Event/index'
import { syncData } from '../../../../Global/MultiViewportMode'
import MouseTip from '../../../../MouseTip'
import { setSplitDirection } from '../../../../Global/SplitScreen'
class GroundText extends Base {
/**
* @constructor
* @param sdk
* @description 贴地文字
* @param options {object} 属性
* @param options.show=true {boolean} 显示/隐藏
* @param options.text {string} 文字
* @param options.angle=0 {number} 旋转角度
* @param options.scale=1 {number} 比例
* @param {object} options.position 经纬度和高度{lon,lat,alt}
* @param {Array.<object>} options.positions 矩形坐标数组 [最西端的经度,最南端的纬度,最东经度,最北纬度]
* @param _Dialog {object} 弹框事件
* @param _Dialog.confirmCallBack {function} 弹框确认时的回调
* */
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
this.options.text = options.text || '未命名对象'
this.options.name = this.options.text
this.options.show =
options.show || options.show === false ? options.show : true
this.options.angle = options.angle || 0
this.options.scale =
options.scale || options.scale === 0 ? options.scale : 1
this.options.fontSize = options.fontSize || 20
this.options.duration =
options.duration || options.duration === 0 ? options.duration : 50000
this.options.speed =
options.speed || options.speed === 0 ? options.speed : 1
this.options.color = options.color || '#FFC107'
this.options.position = options.position
this.entity
this._positionEditing = false
this.Dialog = _Dialog
this._EventBinding = new EventBinding()
this._elms = {}
this.previous = {
position: { ...this.options.position }
}
this.event = new MouseEvent(this.sdk)
this.sdk.addIncetance(this.options.id, this)
this.create()
}
get text() {
return this.options.text
}
set text(v) {
this.options.text = v
if (this.entity) {
let canvas = this.getcanvas()
let ratio = canvas.height / canvas.width
this.entity.rectangle.material = new Cesium.CustomMaterialSource({
image: canvas.toDataURL('image/png'),
color: this.options.color,
repeat: new Cesium.Cartesian2(1.0, 1.0),
duration: this.options.duration / this.options.speed,
fltr: false
})
this.entity.rectangle.coordinates = new Cesium.CallbackProperty(() => {
let gap =
Math.abs(Math.cos((Math.PI / 180) * this.options.position.lat)) *
(0.0001 * this.options.scale)
let fromDegreesArray = [
this.options.position.lng - (0.0001 * this.options.scale) / ratio,
this.options.position.lat - gap,
this.options.position.lng + (0.0001 * this.options.scale) / ratio,
this.options.position.lat + gap
]
return Cesium.Rectangle.fromDegrees(...fromDegreesArray)
}, false)
}
this._elms.text &&
this._elms.text.forEach(item => {
item.value = v
})
}
get angle() {
return this.options.angle
}
set angle(v) {
this.options.angle = v
this._elms.angle &&
this._elms.angle.forEach(item => {
item.value = v
})
}
get scale() {
return this.options.scale
}
set scale(v) {
this.options.scale = v
this._elms.scale &&
this._elms.scale.forEach(item => {
item.value = v
})
}
get duration() {
return this.options.duration
}
set duration(v) {
this.options.duration = v
let canvas = this.getcanvas()
this.entity.rectangle.material = new Cesium.CustomMaterialSource({
image: canvas.toDataURL('image/png'),
color: this.options.color,
repeat: new Cesium.Cartesian2(1.0, 1.0),
duration: this.options.duration / this.options.speed,
fltr: false
})
this._elms.duration &&
this._elms.duration.forEach(item => {
item.value = v
})
}
get speed() {
return this.options.speed
}
set speed(v) {
this.options.speed = v
let canvas = this.getcanvas()
this.entity.rectangle.material = new Cesium.CustomMaterialSource({
image: canvas.toDataURL('image/png'),
color: this.options.color,
repeat: new Cesium.Cartesian2(1.0, 1.0),
duration: this.options.duration / this.options.speed,
fltr: false
})
this._elms.speed &&
this._elms.speed.forEach(item => {
item.value = v
})
}
get color() {
return this.options.color
}
set color(v) {
this.options.color = v
let canvas = this.getcanvas()
this.entity.rectangle.material = new Cesium.CustomMaterialSource({
image: canvas.toDataURL('image/png'),
color: this.options.color,
repeat: new Cesium.Cartesian2(1.0, 1.0),
duration: this.options.duration / this.options.speed,
fltr: false
})
if (this._elms.color) {
this._elms.color.forEach((item, i) => {
let colorPicker = new YJColorPicker({
el: item.el,
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: v,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: c => {
this.color = c
}, //点击确认按钮事件回调
clear: () => {
this.color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
this._elms.color[i] = colorPicker
})
}
}
create() {
// let gap = Math.abs(Math.cos(Math.PI/180 * this.options.position.lat)) * (0.0001*this.options.scale)
// let fromDegreesArray = [
// this.options.position.lng - 0.05, this.options.position.lat - 0.05,
// this.options.position.lng + 0.05, this.options.position.lat - 0.05,
// this.options.position.lng + 0.05, this.options.position.lat + 0.05,
// this.options.position.lng - 0.05, this.options.position.lat + 0.05,
// ]
let canvas = this.getcanvas()
let ratio = canvas.height / canvas.width
let height = ((this.options.positions[2] - this.options.positions[0])/2) * ratio
this.options.positions[1] = this.options.positions[3] - height
this.entity = this.sdk.viewer.entities.add({
id: this.options.id,
show: this.options.show,
rectangle: {
coordinates: new Cesium.CallbackProperty(() => {
let gap =
Math.abs(Math.cos((Math.PI / 180) * this.options.position.lat)) *
(0.0001 * this.options.scale)
let fromDegreesArray = [
this.options.position.lng - (0.0001 * this.options.scale) / ratio,
this.options.position.lat - gap,
// this.options.position.lng + 0.05, this.options.position.lat - 0.05,
this.options.position.lng + (0.0001 * this.options.scale) / ratio,
this.options.position.lat + gap
// this.options.position.lng - 0.05, this.options.position.lat + 0.05,
]
return Cesium.Rectangle.fromDegrees(...this.options.positions)
}, false),
outline: true,
outlineColor: Cesium.Color.RED,
outlineWidth: 10,
rotation: new Cesium.CallbackProperty(() => {
return Cesium.Math.toRadians(this.options.angle)
}, false),
stRotation: new Cesium.CallbackProperty(() => {
return Cesium.Math.toRadians(this.options.angle)
}, false)
}
})
if (this.sdk.viewer._element.className === 'cesium-viewer 2d') {
this.entity.rectangle.height = 1000000
}
syncData(this.sdk, this.options.id)
if(this.options.show) {
setSplitDirection(0, this.options.id)
}
}
// 编辑框
async edit(state) {
let _this = this
this.originalOptions = this.deepCopyObj(this.options)
this._element_style = null
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
if (state) {
this._element_style = document.createElement('style')
this._element_style.type = 'text/css'
this._element_style.setAttribute('data-name', 'YJ_style_dialog')
this._element_style.innerHTML = css()
this._DialogObject = await new Dialog(
this.sdk,
this.originalOptions,
{
title: '编辑属性',
left: '180px',
top: '100px',
confirmCallBack: options => {
this.text = this.text.trim()
if (!this.text) {
this.text = '未命名对象'
}
this.originalOptions = this.deepCopyObj(this.options)
this._DialogObject.close()
this.Dialog.confirmCallBack &&
this.Dialog.confirmCallBack(this.originalOptions)
syncData(this.sdk, this.options.id)
},
resetCallBack: () => {
this.reset()
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
},
removeCallBack: () => {
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
},
closeCallBack: () => {
this.reset()
this.positionEditing = false
// this.entity.style = new Cesium.Cesium3DTileStyle({
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
// show: true,
// });
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
},
showCallBack: show => {
this.show = show
this.Dialog.showCallBack && this.Dialog.showCallBack()
},
translationalCallBack: () => {
this.positionEditing = !this.positionEditing
}
},
true
)
document.getElementsByTagName('head')[0].appendChild(this._element_style)
let contentElm = document.createElement('div')
contentElm.innerHTML = html()
this._DialogObject.contentAppChild(contentElm)
let all_elm = contentElm.getElementsByTagName('*')
this._EventBinding.on(this, all_elm)
this._elms = this._EventBinding.element
// 颜色组件
let colorPicker = new YJColorPicker({
el: contentElm.getElementsByClassName('color')[0],
size: 'mini', //颜色box类型
alpha: true, //是否开启透明度
defaultColor: this.color,
disabled: false, //是否禁止打开颜色选择器
openPickerAni: 'opacity', //打开颜色选择器动画
sure: color => {
this.color = color
}, //点击确认按钮事件回调
clear: () => {
this.color = 'rgba(255,255,255,1)'
} //点击清空按钮事件回调
})
this._elms.color = [colorPicker]
} else {
if (this._element_style) {
document
.getElementsByTagName('head')[0]
.removeChild(this._element_style)
this._element_style = null
}
if (this._DialogObject && this._DialogObject.remove) {
this._DialogObject.remove()
this._DialogObject = null
}
}
}
/**@desc 打开平移功能
*
* @memberOf Source
* @param status {boolean}
*
* */
set positionEditing(status) {
if (!this.sdk || !this.sdk.viewer || !this.entity) {
return
}
this._positionEditing = status
this.previous = {
position: { ...this.options.position }
}
if (status === true) {
this.tip && this.tip.destroy()
this.tip = new MouseTip('点击鼠标左键确认,右键取消', this.sdk)
this.event.mouse_move((movement, cartesian) => {
let position = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
this.options.position.lng = position.lng
this.options.position.lat = position.lat
this.options.position.alt = position.alt
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.mouse_left((movement, cartesian) => {
let position = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
this.options.position.lng = position.lng
this.options.position.lat = position.lat
this.options.position.alt = position.alt
this.event.mouse_move(() => {})
this.event.mouse_left(() => {})
this.event.mouse_right(() => {})
this.positionEditing = false
})
this.event.mouse_right((movement, cartesian) => {
this.options.position.lng = this.previous.position.lng
this.options.position.lat = this.previous.position.lat
this.options.position.alt = this.previous.position.alt
this.positionEditing = false
})
} else {
if (this.event) {
this.event.mouse_move(() => { })
this.event.mouse_left(() => { })
this.event.mouse_right(() => { })
}
this.tip && this.tip.destroy()
}
}
get positionEditing() {
return this._positionEditing
}
/**
* 飞到
*/
async flyTo(options = {}) {
let canvas = this.getcanvas()
let ratio = canvas.height / canvas.width
if (this.options.customView) {
this.sdk.viewer.camera.flyTo({
destination: this.options.customView.position,
orientation: this.options.customView.orientation
})
} else {
let gap =
Math.abs(Math.cos((Math.PI / 180) * this.options.position.lat)) *
(0.0001 * this.options.scale)
let fromDegreesArray = [
[
this.options.position.lng - (0.0001 * this.options.scale) / ratio,
this.options.position.lat - gap
],
[
this.options.position.lng + (0.0001 * this.options.scale) / ratio,
this.options.position.lat + gap
]
]
let height = await this.getClampToHeight(this.options.position)
let positionArray = []
for (let i = 0; i < fromDegreesArray.length; i++) {
let a = Cesium.Cartesian3.fromDegrees(...fromDegreesArray[i], height)
positionArray.push(a.x, a.y, a.z)
}
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.sdk.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: options.orientation || {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
}
reset() {
if (!this.entity) {
return
}
this.options = this.deepCopyObj(this.originalOptions)
this.text = this.originalOptions.text
this.angle = this.originalOptions.angle
this.scale = this.originalOptions.scale
this.color = this.originalOptions.color
}
async remove() {
this.event && this.event.destroy()
this.tip && this.tip.destroy()
this.sdk.viewer.entities.remove(this.entity)
this.entity = null
if (this._DialogObject && !this._DialogObject.isDestroy) {
this._DialogObject.close()
this._DialogObject = null
}
await this.sdk.removeIncetance(this.options.id)
await syncData(this.sdk, this.options.id)
}
getcanvas() {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
let textArray = this.options.text.split('\n')
let maxWidth = 0
for (let i = 0; i < textArray.length; i++) {
ctx.font = 200 + 'px serif'
const width = ctx.measureText(textArray[i]).width
if (maxWidth < width) {
maxWidth = width
}
}
canvas.width = maxWidth
canvas.height = 220 * textArray.length
for (let i = 0; i < textArray.length; i++) {
ctx.font = 200 + 'px serif'
ctx.fillStyle = 'rgba(255, 255, 255, 0)'
ctx.fillRect(0, 0, maxWidth + 30, 210)
ctx.fillStyle = this.options.color
ctx.font = '200px serif'
ctx.fillText(textArray[i], 0, 210 * (i + 1))
}
return canvas
}
}
export default GroundText