Files
sdk4.0/src/Obj/Base/TextObject/StandText/index.js

724 lines
26 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 Dialog from '../../../Element/Dialog';
import EventBinding from '../../../Element/Dialog/eventBinding';
import cy_tabs from "../../../Element/cy_html_tabs";
import richText from "../../../Element/richText";
import { html } from "./_element";
import Base from "../../index";
import LabelObject from '../../LabelObject'
import MouseEvent from '../../../../Event'
import MouseTip from '../../../../MouseTip'
import { syncData } from '../../../../Global/MultiViewportMode'
import { setSplitDirection, syncSplitData, setActiveId } from '../../../../Global/SplitScreen'
class StandText extends Base {
/**
* @constructor
* @param sdk
* @description 立体文字
* @param options {object}
* @param options.text {string} 文字
* @param options.color="#FFC107" {string} 颜色
* @param options.speed=1 {number} 文字移动速度
* @param {Array.<object>} positions 经纬度和高度的列表,值交替 [{lon,lat,alt},...]
* @param _Dialog {object} 弹框事件
* @param _Dialog.confirmCallBack {function} 弹框确认时的回调
* */
constructor(sdk, options, _Dialog = {}) {
super(sdk, options);
this.options.text = options.text || "未命名对象"
let textArray = this.options.text.split('\n')
for (let i = 0; i < textArray.length; i++) {
if (textArray[i].length > 80) {
textArray[i] = textArray[i].slice(0, 80-textArray[i].length)
}
}
if (textArray.length > 70) {
textArray.splice(70 - textArray.length)
}
this.options.text = textArray.join('\n')
this.options.color = options.color || "#FFC107"
// this.options.cornerType = options.cornerType || 'MITERED'
this.options.positions = options.positions
// this.options.material = Number(options.material) || 0
this.options.speed = (options.speed || options.speed === 0) ? options.speed : 1
// this.options.duration = (options.duration || options.duration === 0) ? options.duration : 50000
this.options.show = (options.show || options.show === false) ? options.show : true
this.nodePoints = []
this.entity
this.options.instruct = options.instruct || ""
this.options.operatingPoint = options.operatingPoint || ""
this.options.attribute = options.attribute || {}
this.options.attribute.link = this.options.attribute.link || {}
this.options.attribute.link.content = this.options.attribute.link.content || []
this.options.attribute.camera = this.options.attribute.camera || []
this.options.attributeType = options.attributeType || 'richText'
this.extrudedHeight
this._EventBinding = new EventBinding()
this.Dialog = _Dialog
this._elms = {};
this.sdk.addIncetance(this.options.id, this)
StandText.create(this)
}
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 > 80) {
let _error = '行超过80个字符,请按回车Enter继续输入'
window.ELEMENT && window.ELEMENT.Message({
message: _error,
type: 'warning',
duration: 1000
});
textArray[i] = textArray[i].slice(0, 80-textArray[i].length)
}
}
if (textArray.length > 70) {
textArray.splice(70 - textArray.length)
let _error = '超过最大输入字符'
window.ELEMENT && window.ELEMENT.Message({
message: _error,
type: 'warning',
duration: 1000
});
}
this.options.text = textArray.join('\n')
if (this.entity) {
let positions = this.options.positions
let fromDegreesArray = []
let minimumHeights = []
let maximumHeights = []
let material = this.getMaterial()
let width = this.computeDistance2(positions)
let extrudedHeight = this.aspectRatio ? (width / this.aspectRatio) : 0
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
this.entity.wall.material = material
this.entity.wall.maximumHeights = maximumHeights
this.entity.wall.minimumHeights = minimumHeights
}
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.wall.material = this.getMaterial()
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 material() {
// return this.options.material
// }
// set material(v) {
// this.options.material = Number(v)
// this.entity.wall.material = this.getMaterial()
// this._elms.material && this._elms.material.forEach((item) => {
// item.value = v
// })
// }
get speed() {
return this.options.speed
}
set speed(v) {
this.options.speed = v
this.entity.wall.material = this.getMaterial()
this._elms.speed && this._elms.speed.forEach((item) => {
item.value = v
})
}
// get attributeLink() {
// return this.options.attribute.link.content
// }
// set attributeLink(v) {
// this.options.attribute.link.content = v
// if (!this._DialogObject || !this._DialogObject._element || !this._DialogObject._element.content) {
// return
// }
// let table = this._DialogObject._element.content.getElementsByClassName('attribute-content-link')[1].getElementsByClassName('table')[0]
// let tableContent = table.getElementsByClassName('table-body')[0]
// tableContent.innerHTML = ''
// if (this.options.attribute.link.content.length > 0) {
// table.getElementsByClassName('table-empty')[0].style.display = 'none'
// }
// else {
// table.getElementsByClassName('table-empty')[0].style.display = 'flex'
// }
// for (let i = 0; i < this.options.attribute.link.content.length; i++) {
// let tr = `
// <div class="tr">
// <div class="td">` + this.options.attribute.link.content[i].name + `</div>
// <div class="td">` + this.options.attribute.link.content[i].url + `</div>
// <div class="td">
// <button class="text" @click="linkEdit">编辑</button>
// <button class="text" @click="linkDelete">删除</button>
// </div>
// </div>`
// let trElm = document.createRange().createContextualFragment(tr)
// tableContent.appendChild(trElm)
// }
// let item = tableContent.getElementsByClassName('tr')
// let fun = {
// linkEdit: async (index) => {
// this.attributeLink = await this.options.attribute.link.content
// let table = this._DialogObject._element.content.getElementsByClassName('attribute-content-link')[1].getElementsByClassName('table')[0]
// let tableContent = table.getElementsByClassName('table-body')[0]
// let item = tableContent.getElementsByClassName('tr')
// for (let i = 0; i < item.length; i++) {
// if (index === i) {
// let html = `
// <div class="td">
// <input class="input" type="text">
// </div>
// <div class="td">
// <div class="input-group">
// <input class="input" type="text" style="width: 140px;">
// <input type="file" accept=".mp4, .pdf" class="file-select" index="`+ i + `" style="display:none">
// <button @click="fileSelect">...</button>
// </div>
// </div>
// <div class="td">
// <button class="text" @click="confirmEdit">确认</button>
// <button class="text" @click="cancelEdit">取消</button>
// </div>`
// item[i].innerHTML = html
// let td = item[i].getElementsByClassName('td')
// td[0].getElementsByClassName('input')[0].value = this.options.attribute.link.content[index].name
// td[1].getElementsByClassName('input')[0].value = this.options.attribute.link.content[index].url
// let btn = item[i].getElementsByTagName('button')
// for (let n = 0; n < btn.length; n++) {
// for (let m of btn[n].attributes) {
// if (m.name === '@click') {
// btn[n].addEventListener('click', (e) => {
// if (typeof (fun[m.value]) === 'function') {
// fun[m.value]({ name: td[0].getElementsByClassName('input')[0].value, url: td[1].getElementsByClassName('input')[0].value }, i)
// }
// });
// btn[n].attributes.removeNamedItem(m.name)
// break
// }
// }
// }
// break
// }
// }
// },
// linkDelete: (i) => {
// this.options.attribute.link.content.splice(i, 1)
// this.attributeLink = this.options.attribute.link.content
// },
// confirmEdit: (value, i) => {
// this.options.attribute.link.content[i] = value
// this.attributeLink = this.options.attribute.link.content
// },
// cancelEdit: () => {
// this.attributeLink = this.options.attribute.link.content
// },
// fileSelect: (value, i) => {
// let fileElm = item[i].getElementsByClassName('file-select')[0]
// fileElm.click()
// fileElm.removeEventListener('change', fileSelect)
// fileElm.addEventListener('change', fileSelect)
// }
// }
// let fileSelect = (event) => {
// if (event.target.value) {
// let td = item[event.target.getAttribute('index')].getElementsByClassName('td')
// td[1].getElementsByClassName('input')[0].value = event.target.value
// event.target.value = null
// }
// }
// for (let i = 0; i < item.length; i++) {
// let btn = item[i].getElementsByTagName('button')
// for (let n = 0; n < btn.length; n++) {
// for (let m of btn[n].attributes) {
// if (m.name === '@click') {
// btn[n].addEventListener('click', (e) => {
// if (typeof (fun[m.value]) === 'function') {
// fun[m.value](i)
// }
// });
// btn[n].attributes.removeNamedItem(m.name)
// break
// }
// }
// }
// }
// }
get attributeCamera() {
return this.options.attribute.camera
}
set attributeCamera(v) {
this.options.attribute.camera = v
}
//创建
static async create(that) {
// console.log(new Cesium.CustomMaterialSource(), new Cesium.PolylineTrailLinkMaterialProperty())
let positions = that.options.positions
let fromDegreesArray = []
let minimumHeights = []
let maximumHeights = []
let material = that.getMaterial()
let width = that.computeDistance2(positions)
let extrudedHeight = that.aspectRatio ? (width / that.aspectRatio) : 0
// aspectRatio
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
that.entity = that.sdk.viewer.entities.add({
id: that.options.id,
show: that.options.show,
wall: {
positions: Cesium.Cartesian3.fromDegreesArray(fromDegreesArray),
cornerType: Cesium.CornerType.MITERED,
maximumHeights: maximumHeights,
minimumHeights: minimumHeights,
material: material,
},
// wall: {
// positions: Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray),
// maximumHeights: maximumHeights,
// minimumHeights: minimumHeights,
// material: new Cesium.PolylineTrailLinkMaterialProperty({duration: 1500}),
// outline: true,
// outlineColor: Cesium.Color.BLACK,
// }
})
syncData(that.sdk, that.options.id)
if(that.options.show) {
setSplitDirection(0, that.options.id)
}
}
// 编辑框
async edit(state) {
let _this = this
this.originalOptions = this.deepCopyObj(this.options)
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
if (state) {
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.Dialog.closeCallBack && this.Dialog.closeCallBack()
for (let i = 0; i < this.nodePoints.length; i++) {
this.sdk.viewer.entities.remove(this.nodePoints[i])
}
this.nodePoints = []
YJ.Measure.SetMeasureStatus(false)
this.event && this.event.destroy()
this.tip && this.tip.destroy()
},
showCallBack: (show) => {
this.options.show = show
this.originalOptions.show = show
this.show = show
this.Dialog.showCallBack && this.Dialog.showCallBack()
},
secondaryEditCallBack: () => {
StandText.nodeEdit(this)
}
})
this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' stand-text'
let contentElm = document.createElement('div');
contentElm.innerHTML = html(this)
this._DialogObject.contentAppChild(contentElm)
this.attributeType = this.options.attributeType
this.attributeCamera = this.options.attribute.camera
// 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 all_elm = contentElm.getElementsByTagName("*")
this._EventBinding.on(this, all_elm)
this._elms = this._EventBinding.element
this._elms.color = [colorPicker]
} else {
if (this._DialogObject && this._DialogObject.remove) {
this._DialogObject.remove()
this._DialogObject = null
}
}
}
reset() {
if (!this.entity) {
return
}
this.options = this.deepCopyObj(this.originalOptions)
this.text = this.originalOptions.text
this.color = this.originalOptions.color
this.speed = this.originalOptions.speed
let positions = this.options.positions
let fromDegreesArray = []
let minimumHeights = []
let maximumHeights = []
let width = this.computeDistance2(positions)
let extrudedHeight = this.aspectRatio ? (width / this.aspectRatio) : 0
// aspectRatio
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
this.entity.wall.positions = Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)
}
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)
}
getMaterial() {
let material
let canvas = this.getcanvas()
material = new Cesium.CustomMaterialSource({
image: canvas.toDataURL("image/png"),
color: this.options.color,
repeat: new Cesium.Cartesian2(1, 1.0),
duration: 50000 / this.options.speed,
fltr: false
})
return material
}
getcanvas() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')
let textArray = this.options.text.split('\n')
for (let i = 0; i < textArray.length; i++) {
if (textArray[i].length > 80) {
textArray[i] = textArray[i].slice(0, 80-textArray[i].length)
}
}
if (textArray.length > 70) {
textArray.splice(70 - textArray.length)
}
this.options.text = textArray.join('\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 = 'rgba(255, 255, 255, 1)';
ctx.font = "200px serif";
ctx.fillText(textArray[i], 0, 210 * (i+1));
}
this.aspectRatio = this.options.text ? (canvas.width / canvas.height) : 0
return canvas
}
/**
* 打开富文本框
*/
openRichTextEditor(e) {
richText.open(this.options.id, this.options.text, this.options.richTextContent)
richText.primaryCallBack = (content) => {
this.options.richTextContent = content
}
}
static nodeEdit(that, cb = () => { }) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
YJ.Measure.SetMeasureStatus(true)
that.tip = new MouseTip('请选择一个顶点,右键取消', that.sdk)
that.event = new MouseEvent(that.sdk)
that.nodePoints = []
let selectPoint
let originalPosition
let positions = that.options.positions
let fromDegreesArray = []
let minimumHeights = []
let maximumHeights = []
let width = that.computeDistance2(positions)
let extrudedHeight = that.aspectRatio ? (width / that.aspectRatio) : 0
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
let isAdd = false
let leftEvent = (movement, cartesian) => {
if (selectPoint) {
isAdd = true
let pos3 = that.sdk.viewer.scene.clampToHeight(cartesian, [that.entity])
that.options.positions[selectPoint.index] = that.cartesian3Towgs84(pos3, that.sdk.viewer)
originalPosition = that.options.positions[selectPoint.index]
let entity = that.sdk.viewer.entities.add({
name: 'node-secondary-edit-point',
position: Cesium.Cartesian3.fromDegrees(that.options.positions[selectPoint.index].lng, that.options.positions[selectPoint.index].lat, that.options.positions[selectPoint.index].alt),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
width: 15,
height: 15,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
},
})
that.nodePoints.splice(selectPoint.index, 0, entity)
that.options.positions.splice(selectPoint.index, 0, that.options.positions[selectPoint.index])
let positions = that.options.positions
fromDegreesArray = []
minimumHeights = []
maximumHeights = []
width = that.computeDistance2(positions)
extrudedHeight = that.aspectRatio ? (width / that.aspectRatio) : 0
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
that.tip.setPosition(
cartesian,
movement.position.x,
movement.position.y
)
}
else {
var pick = that.sdk.viewer.scene.pick(movement.position);
if (pick && pick.id && pick.id.name && pick.id.name === 'node-secondary-edit-point') {
selectPoint = pick.id
that.nodePoints.splice(pick.id.index, 1)
that.sdk.viewer.entities.remove(pick.id)
that.tip.set_text('左键开始右键结束CTRL+右键撤销')
originalPosition = that.cartesian3Towgs84(cartesian, that.sdk.viewer)
that.entity.wall.positions = new Cesium.CallbackProperty(function () {
return Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)
}, false)
that.entity.wall.maximumHeights = new Cesium.CallbackProperty(function () {
return maximumHeights
}, false)
that.entity.wall.minimumHeights = new Cesium.CallbackProperty(function () {
return minimumHeights
}, false)
}
}
}
let rightEvent = (movement, cartesian) => {
if (selectPoint) {
that.options.positions[selectPoint.index] = originalPosition
if(isAdd) {
that.options.positions.splice(selectPoint.index, 1)
}
cb(null, that.options.positions)
}
let positions = that.options.positions
fromDegreesArray = []
minimumHeights = []
maximumHeights = []
width = that.computeDistance2(positions)
extrudedHeight = that.aspectRatio ? (width / that.aspectRatio) : 0
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
that.entity.wall.positions = Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)
for (let i = 0; i < that.nodePoints.length; i++) {
that.sdk.viewer.entities.remove(that.nodePoints[i])
}
that.nodePoints = []
YJ.Measure.SetMeasureStatus(false)
that.event.destroy()
that.tip.destroy()
}
that.event.mouse_left(leftEvent)
that.event.mouse_right(rightEvent)
that.event.mouse_move((movement, cartesian) => {
if (selectPoint) {
let pos3 = that.sdk.viewer.scene.clampToHeight(cartesian, [that.entity])
that.options.positions[selectPoint.index] = that.cartesian3Towgs84(pos3, that.sdk.viewer)
let positions = that.options.positions
fromDegreesArray = []
minimumHeights = []
maximumHeights = []
width = that.computeDistance2(positions)
extrudedHeight = that.aspectRatio ? (width / that.aspectRatio) : 0
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
minimumHeights.push(positions[i].alt)
maximumHeights.push(positions[i].alt + extrudedHeight)
}
}
that.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
that.event.mouse_right_keyboard_ctrl((movement, cartesian) => {
if (selectPoint) {
that.options.positions.pop()
that.sdk.viewer.entities.remove(that.nodePoints[that.nodePoints.length - 1])
that.nodePoints.pop()
if (selectPoint.index === that.options.positions.length) {
if (that.nodePoints[selectPoint.index - 1]) {
selectPoint = that.nodePoints[selectPoint.index - 1]
}
else {
selectPoint.index = 0
}
}
}
})
that.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
that.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
rightEvent(pos, cartesian)
}
else {
leftEvent(pos, cartesian)
}
})
})
for (let i = 0; i < that.options.positions.length; i++) {
let entity = that.sdk.viewer.entities.add({
name: 'node-secondary-edit-point',
index: i,
position: Cesium.Cartesian3.fromDegrees(that.options.positions[i].lng, that.options.positions[i].lat, that.options.positions[i].alt),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
width: 15,
height: 15,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
},
})
that.nodePoints.push(entity)
}
}
}
}
export default StandText