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

536 lines
18 KiB
JavaScript

// 3D文字(未完成)
import Base from "../../index";
import Dialog from '../../../Element/Dialog';
import { html, css } from "./_element";
import MouseEvent from '../../../../Event'
import { FontLoader } from '../../../../../static/3rdparty/three/jsm/loaders/FontLoader.js';
import { TextGeometry } from '../../../../../static/3rdparty/three/jsm/geometries/TextGeometry.js';
import * as variable from '../../../../../static/3rdparty/three/fonts/FZZongYi-M05S_regular.typeface.json'
import { setSplitDirection, syncSplitData, setActiveId } from '../../../../Global/SplitScreen'
class Text3D extends Base {
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options);
this.options.positions = options.positions = options.positions || {}
this.options.positions.lng = options.positions.lng
this.options.positions.lat = options.positions.lat
this.options.positions.alt = options.positions.alt
this.options.color = options.color || "#00d9ff"
this.options.text = options.text || "未命名对象"
this.options.extrudedHeight = options.extrudedHeight || 10
this.operate = {}
this.Dialog = _Dialog
this._elms = {};
this.event = new MouseEvent(this.sdk)
this.sdk.addIncetance(this.options.id, this)
Text3D.create(this)
}
get text() {
return this.options.text
}
set text(v) {
this.options.text = v
this.update()
this._elms.text && this._elms.text.forEach((item) => {
item.value = v
})
}
get color() {
return this.options.color
}
set color(v) {
this.options.color = v
this.entity.appearance.material = new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: Cesium.Color.fromCssColorString(this.options.color)
}
}
})
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
})
}
}
get extrudedHeight() {
return this.options.extrudedHeight
}
set extrudedHeight(v) {
this.options.extrudedHeight = v
this.update()
this._elms.extrudedHeight && this._elms.extrudedHeight.forEach((item) => {
item.value = v
})
}
get lng() {
return this.options.positions.lng
}
set lng(v) {
this.options.positions.lng = v
this.update()
this._elms.lng && this._elms.lng.forEach((item) => {
item.value = v
})
}
get lat() {
return this.options.positions.lat
}
set lat(v) {
this.options.positions.lat = v
this.update()
this._elms.lat && this._elms.lat.forEach((item) => {
item.value = v
})
}
get alt() {
return this.options.positions.alt
}
set alt(v) {
this.options.positions.alt = v
this.update()
this._elms.alt && this._elms.alt.forEach((item) => {
item.value = v
})
}
static create(that) {
const loader = new FontLoader();
let textGeo = new TextGeometry(that.options.text, {
font: loader.parse(variable.default),
height: 0,
size: 1,
depth: 0,
curveSegments: 2,
bevelEnabled: false
});
if(!textGeo || !textGeo.attributes) {
return
}
let data = textGeo.attributes.position.array
let fromDegreesArray = []
for (let i = 0; i < data.length; i += 3) {
fromDegreesArray.push(data[i] + that.lng, data[i + 1] + that.lat, data[i + 2])
}
const instances = []
for (let i = 0; i < fromDegreesArray.length; i += 9) {
let instance = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights([fromDegreesArray[i], fromDegreesArray[i + 1], fromDegreesArray[i + 2], fromDegreesArray[i + 3], fromDegreesArray[i + 4], fromDegreesArray[i + 5], fromDegreesArray[i + 6], fromDegreesArray[i + 7], fromDegreesArray[i + 8]])),
vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
extrudedHeight: that.alt + that.extrudedHeight,
height: that.alt
})
});
instances.push(instance)
}
that.entity = that.sdk.viewer.scene.primitives.add(new Cesium.Primitive({
// allowPicking: false,
asynchronous: false,
releaseGeometryInstances: false,
geometryInstances: instances,
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: Cesium.Color.fromCssColorString(that.options.color)
}
}
})
})
}));
if(that.options.show) {
setSplitDirection(0, that.options.id)
}
// setTimeout(() => {
// let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(100, 20, 0))
// that.entity.modelMatrix = Cesium.Matrix4.multiply(that.entity.modelMatrix, m, new Cesium.Matrix4())
// }, 5000);
}
// 编辑框
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.options, {
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)
syncSplitData(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.Dialog.closeCallBack && this.Dialog.closeCallBack()
},
showCallBack: (show) => {
this.options.show = show
this.originalOptions.show = show
this.show = show
this.Dialog.showCallBack && this.Dialog.showCallBack()
},
translationalCallBack: () => {
this.positionEditing = !this.positionEditing
},
})
document.getElementsByTagName('head')[0].appendChild(this._element_style);
let contentElm = document.createElement('div');
contentElm.innerHTML = html(this)
this._DialogObject.contentAppChild(contentElm)
// setTimeout(() => {
// this.attributeLink = this.options.attribute.link.content
// this.cameraSelect()
// }, 500);
// 创建标签页
// let tabsElm = new cy_tabs('radar-scan-edit-tabs')
// 颜色组件
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)'
},//点击清空按钮事件回调
})
let labelColorPicker = new YJColorPicker({
el: contentElm.getElementsByClassName("labelColor")[0],
size: 'mini',//颜色box类型
alpha: true,//是否开启透明度
defaultColor: this.labelColor,
disabled: false,//是否禁止打开颜色选择器
openPickerAni: 'opacity',//打开颜色选择器动画
sure: (color) => {
this.labelColor = color
},//点击确认按钮事件回调
clear: () => {
this.labelColor = 'rgba(255,255,255,1)'
},//点击清空按钮事件回调
})
let lineColorPicker = new YJColorPicker({
el: contentElm.getElementsByClassName("labelLineColor")[0],
size: 'mini',//颜色box类型
alpha: true,//是否开启透明度
defaultColor: this.labelLineColor,
disabled: false,//是否禁止打开颜色选择器
openPickerAni: 'opacity',//打开颜色选择器动画
sure: (color) => {
this.labelLineColor = color
},//点击确认按钮事件回调
clear: () => {
this.labelLineColor = 'rgba(255,255,255,1)'
},//点击清空按钮事件回调
})
let labelBackgroundColorStartPicker = new YJColorPicker({
el: contentElm.getElementsByClassName("labelBackgroundColorStart")[0],
size: 'mini',
alpha: true,
defaultColor: this.labelBackgroundColorStart,
disabled: false,
openPickerAni: 'opacity',
sure: (color) => {
this.labelBackgroundColorStart = color
},
clear: () => {
this.labelBackgroundColorStart = 'rgba(255,255,255,1)'
},
})
let labelBackgroundColorEndPicker = new YJColorPicker({
el: contentElm.getElementsByClassName("labelBackgroundColorEnd")[0],
size: 'mini',
alpha: true,
defaultColor: this.labelBackgroundColorEnd,
disabled: false,
openPickerAni: 'opacity',
sure: (color) => {
this.labelBackgroundColorEnd = color
},
clear: () => {
this.labelBackgroundColorEnd = 'rgba(255,255,255,1)'
},
})
let all_elm = contentElm.getElementsByTagName("*")
Text3D.EventBinding(this, all_elm)
this._elms.color = [colorPicker]
this._elms.labelColor = [labelColorPicker]
this._elms.labelLineColor = [lineColorPicker]
this._elms.labelBackgroundColorStart = [labelBackgroundColorStartPicker]
this._elms.labelBackgroundColorEnd = [labelBackgroundColorEndPicker]
} 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.operate.positionEditing = status
if (status === true) {
this.picking = false
this.previous = {
positions: { ...this.options.positions }
}
this.event.mouse_move((movement, cartesian) => {
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
this.options.positions.lng = positions.lng
this.options.positions.lat = positions.lat
this.options.positions.alt = positions.alt
})
this.event.mouse_left((movement, cartesian) => {
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
this.options.positions.lng = positions.lng
this.options.positions.lat = positions.lat
this.options.positions.alt = positions.alt
this.previous = {
positions: { ...this.options.positions }
}
this.update()
this.event.mouse_move(() => { })
this.event.mouse_left(() => { })
this.event.mouse_right(() => { })
this.positionEditing = false
})
this.event.mouse_right((movement, cartesian) => {
this.positionEditing = false
})
}
else {
this.picking = true
this.event.mouse_move(() => { })
this.event.mouse_left(() => { })
this.event.mouse_right(() => { })
this.options.positions.lng = this.previous.positions.lng
this.options.positions.lat = this.previous.positions.lat
this.options.positions.alt = this.previous.positions.alt
}
}
get positionEditing() {
return this.operate.positionEditing
}
update() {
if (this.entity) {
let modelMatrix = this.entity.modelMatrix
const loader = new FontLoader();
let textGeo = new TextGeometry(this.options.text, {
font: loader.parse(variable.default),
height: 0,
size: 1,
depth: 0,
curveSegments: 2,
bevelEnabled: false
});
if(!textGeo ||!textGeo.attributes) {
return
}
let data = textGeo.attributes.position.array
let fromDegreesArray = []
for (let i = 0; i < data.length; i += 3) {
fromDegreesArray.push(data[i] + this.lng, data[i + 1] + this.lat, data[i + 2])
}
const instances = []
for (let i = 0; i < fromDegreesArray.length; i += 9) {
var instance = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights([fromDegreesArray[i], fromDegreesArray[i + 1], fromDegreesArray[i + 2], fromDegreesArray[i + 3], fromDegreesArray[i + 4], fromDegreesArray[i + 5], fromDegreesArray[i + 6], fromDegreesArray[i + 7], fromDegreesArray[i + 8]])),
vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
extrudedHeight: this.alt + this.extrudedHeight,
height: this.alt
})
});
instances.push(instance)
}
this.sdk.viewer.scene.primitives.remove(this.entity)
this.entity = this.sdk.viewer.scene.primitives.add(new Cesium.Primitive({
// allowPicking: false,
asynchronous: false,
releaseGeometryInstances: false,
geometryInstances: instances,
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: Cesium.Color.fromCssColorString(this.options.color)
}
}
})
})
}));
this.entity.modelMatrix = modelMatrix
// this.lng = this.options.positions.lng
}
}
static EventBinding(that, elements) {
for (let i = 0; i < elements.length; i++) {
let Event = []
let isEvent = false
let removeName = []
if (!elements[i] || !elements[i].attributes) {
continue;
}
for (let m of elements[i].attributes) {
switch (m.name) {
case '@model': {
isEvent = true
if (elements[i].type == 'checkbox') {
Event.push((e) => { that[m.value] = e.target.checked })
elements[i].checked = that[m.value]
}
else {
Event.push((e) => {
let value = e.target.value
if (e.target.type == 'number') {
if (e.data != '.' && (e.data != '-' || e.target.value)) {
value = Number(value)
if ((e.target.max) && value > Number(e.target.max)) {
value = Number(e.target.max)
}
if ((e.target.min) && value < Number(e.target.min)) {
value = Number(e.target.min)
}
that[m.value] = value
}
}
else {
that[m.value] = value
}
})
if (elements[i].nodeName == 'IMG') {
elements[i].src = that[m.value]
}
else {
elements[i].value = that[m.value]
}
}
if (that._elms[m.value]) {
that._elms[m.value].push(elements[i])
}
else {
that._elms[m.value] = [elements[i]]
}
removeName.push(m.name)
break;
}
case '@click': {
elements[i].addEventListener('click', (e) => {
if (typeof (that[m.value]) === 'function') {
that[m.value](e)
}
});
removeName.push(m.name)
// elements[i].attributes.removeNamedItem(m.name)
break;
}
case '@change': {
isEvent = true
Event.push((e) => {
let value = e.target.value
if (e.target.type == 'number' && value != '') {
value = Number(value)
e.target.value = value
}
if (typeof (that[m.value]) === 'function') {
that[m.value](e, value)
}
})
break;
}
}
// elements[i].attributes[m] = undefined
}
for (let n = 0; n < removeName.length; n++) {
elements[i].attributes.removeNamedItem(removeName[n])
}
if (isEvent) {
let ventType = 'input'
if (elements[i].tagName != 'INPUT' || elements[i].type == 'checkbox') {
ventType = 'change'
}
elements[i].addEventListener(ventType, (e) => {
for (let t = 0; t < Event.length; t++) {
Event[t](e)
}
});
}
}
}
}
export default Text3D