8 changed files with 730 additions and 44 deletions
@ -0,0 +1,211 @@ |
|||
import { |
|||
EventDispatcher, |
|||
Matrix4, |
|||
Plane, |
|||
Raycaster, |
|||
Vector2, |
|||
Vector3 |
|||
} from 'three'; |
|||
|
|||
const _plane = new Plane(); |
|||
const _raycaster = new Raycaster(); |
|||
|
|||
const _pointer = new Vector2(); |
|||
const _offset = new Vector3(); |
|||
const _intersection = new Vector3(); |
|||
const _worldPosition = new Vector3(); |
|||
const _inverseMatrix = new Matrix4(); |
|||
|
|||
class DragControls extends EventDispatcher { |
|||
constructor( _objects, _camera, _domElement ) { |
|||
super(); |
|||
|
|||
_domElement.style.touchAction = 'none'; // disable touch scroll
|
|||
|
|||
let _selected = null, _hovered = null; |
|||
|
|||
const _intersections = []; |
|||
|
|||
//
|
|||
|
|||
let isMove = false; |
|||
|
|||
const scope = this; |
|||
|
|||
function activate() { |
|||
_domElement.addEventListener( 'pointermove', onPointerMove ); |
|||
_domElement.addEventListener( 'pointerdown', onPointerDown ); |
|||
_domElement.addEventListener( 'pointerup', onPointerCancel ); |
|||
_domElement.addEventListener( 'pointerleave', onPointerCancel ); |
|||
} |
|||
|
|||
function deactivate() { |
|||
_domElement.removeEventListener( 'pointermove', onPointerMove ); |
|||
_domElement.removeEventListener( 'pointerdown', onPointerDown ); |
|||
_domElement.removeEventListener( 'pointerup', onPointerCancel ); |
|||
_domElement.removeEventListener( 'pointerleave', onPointerCancel ); |
|||
|
|||
_domElement.style.cursor = ''; |
|||
} |
|||
|
|||
function dispose() { |
|||
deactivate(); |
|||
} |
|||
|
|||
function setObjects( objects ) { |
|||
_objects = objects; |
|||
} |
|||
|
|||
function getObjects() { |
|||
return _objects; |
|||
} |
|||
|
|||
function getRaycaster() { |
|||
return _raycaster; |
|||
} |
|||
|
|||
function onPointerMove( event ) { |
|||
|
|||
if ( !scope.enabled || !scope.enabledMove) return; |
|||
|
|||
isMove = true; |
|||
|
|||
updatePointer( event ); |
|||
|
|||
_raycaster.setFromCamera( _pointer, _camera ); |
|||
|
|||
if ( _selected ) { |
|||
|
|||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
|||
|
|||
_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) ); |
|||
|
|||
} |
|||
|
|||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
|||
|
|||
return; |
|||
|
|||
} |
|||
|
|||
// hover support
|
|||
|
|||
if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) { |
|||
|
|||
_intersections.length = 0; |
|||
|
|||
_raycaster.setFromCamera( _pointer, _camera ); |
|||
_raycaster.intersectObjects( _objects, true, _intersections ); |
|||
|
|||
if ( _intersections.length > 0 ) { |
|||
|
|||
const object = _intersections[ 0 ].object; |
|||
|
|||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) ); |
|||
|
|||
if ( _hovered !== object && _hovered !== null ) { |
|||
|
|||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
|||
|
|||
_domElement.style.cursor = 'auto'; |
|||
_hovered = null; |
|||
|
|||
} |
|||
|
|||
if ( _hovered !== object ) { |
|||
|
|||
scope.dispatchEvent( { type: 'hoveron', object: object } ); |
|||
|
|||
_domElement.style.cursor = 'pointer'; |
|||
_hovered = object; |
|||
|
|||
} |
|||
|
|||
} else { |
|||
|
|||
if ( _hovered !== null ) { |
|||
|
|||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
|||
|
|||
_domElement.style.cursor = 'auto'; |
|||
_hovered = null; |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
function onPointerDown( event ) { |
|||
if (scope.enabled === false) return; |
|||
|
|||
updatePointer(event); |
|||
|
|||
_intersections.length = 0; |
|||
|
|||
_raycaster.setFromCamera( _pointer, _camera ); |
|||
let objects = _objects; |
|||
|
|||
_raycaster.intersectObjects( objects, true, _intersections ); |
|||
|
|||
if (_intersections.length > 0) { |
|||
_selected = (scope.transformGroup === true) ? _objects[ 0 ] : _intersections[0].object; |
|||
|
|||
if(scope.enabledMove) { |
|||
_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), _worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
|||
if (_raycaster.ray.intersectPlane(_plane, _intersection)) { |
|||
_inverseMatrix.copy(_selected.parent.matrixWorld).invert(); |
|||
_offset.copy(_intersection).sub(_worldPosition.setFromMatrixPosition(_selected.matrixWorld)); |
|||
} |
|||
|
|||
_domElement.style.cursor = 'move'; |
|||
} |
|||
scope.dispatchEvent( { type: 'dragstart', object: _selected,e:event } ); |
|||
} |
|||
|
|||
isMove = false; |
|||
} |
|||
|
|||
function onPointerCancel(event) { |
|||
if ( scope.enabled === false ) return; |
|||
|
|||
if ( _selected ) { |
|||
scope.dispatchEvent( { type: 'dragend', object: _selected,e:event } ); |
|||
_selected = null; |
|||
}else if(!isMove){ |
|||
// 添加点击空白处的事件
|
|||
scope.dispatchEvent( { type: 'clickblank',e:event } ); |
|||
} |
|||
|
|||
_domElement.style.cursor = _hovered ? 'pointer' : 'auto'; |
|||
} |
|||
|
|||
function updatePointer( event ) { |
|||
const rect = _domElement.getBoundingClientRect(); |
|||
|
|||
_pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; |
|||
_pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; |
|||
} |
|||
|
|||
activate(); |
|||
|
|||
// API
|
|||
|
|||
this.enabled = true; |
|||
this.enabledMove = true; |
|||
this.transformGroup = false; |
|||
|
|||
this.activate = activate; |
|||
this.deactivate = deactivate; |
|||
this.dispose = dispose; |
|||
this.setObjects = setObjects; |
|||
this.getObjects = getObjects; |
|||
this.getRaycaster = getRaycaster; |
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
export { DragControls }; |
|||
@ -0,0 +1,129 @@ |
|||
import { DragControls } from './DragControls.js' |
|||
import * as THREE from 'three' |
|||
import type Viewport from '@/designer/Viewport.ts' |
|||
|
|||
// dragControls 绑定函数
|
|||
let dragStartFn, dragFn, dragEndFn, clickblankFn |
|||
|
|||
export default class EsDragControls { |
|||
protected _dragObjects: THREE.Object3D[] = [] // 拖拽对象
|
|||
dragControls: any |
|||
private onDownPosition: { x: number; y: number } = { x: -1, y: -1 } |
|||
|
|||
viewport: Viewport |
|||
isDragging = false |
|||
|
|||
constructor(viewport) { |
|||
this.viewport = viewport |
|||
|
|||
// 物体拖拽控制器
|
|||
this.dragControls = new DragControls(this._dragObjects, viewport.camera, viewport.renderer.domElement) |
|||
this.dragControls.deactivate() // 默认禁用
|
|||
dragStartFn = this.dragControlsStart.bind(this) |
|||
this.dragControls.addEventListener('dragstart', dragStartFn) |
|||
dragFn = this.drag.bind(this) |
|||
this.dragControls.addEventListener('drag', dragFn) |
|||
dragEndFn = this.dragControlsEnd.bind(this) |
|||
this.dragControls.addEventListener('dragend', dragEndFn) |
|||
// 点击可拖拽物体之外
|
|||
clickblankFn = this.clickblank.bind(this) |
|||
this.dragControls.addEventListener('clickblank', clickblankFn) |
|||
} |
|||
|
|||
set domElement(element: HTMLElement) { |
|||
this.dragControls.setDomElement(element) |
|||
} |
|||
|
|||
setDragObjects(objects: THREE.Object3D[], type: 'eq' | 'push' | 'remove' = 'eq') { |
|||
// 当前拖拽对象为空时加入对象需激活控制器
|
|||
if (this._dragObjects.length === 0) { |
|||
if (objects.length > 0) { |
|||
this.dragControls.activate() |
|||
} |
|||
|
|||
this._dragObjects = objects |
|||
} else { |
|||
// 当前拖拽对象不为空时
|
|||
if (type === 'eq') { |
|||
// 是清空拖拽对象的设置,则禁用控制器
|
|||
if (objects.length === 0) { |
|||
this.dragControls.deactivate() |
|||
} |
|||
|
|||
this._dragObjects = objects |
|||
} else if (type === 'push') { |
|||
this._dragObjects.push(...objects) |
|||
} else if (type === 'remove') { |
|||
this._dragObjects = this._dragObjects.filter((item) => !objects.includes(item)) |
|||
} |
|||
} |
|||
|
|||
this.dragControls.setObjects(this._dragObjects) |
|||
} |
|||
|
|||
// 拖拽开始
|
|||
dragControlsStart(e) { |
|||
// 右键拖拽不响应
|
|||
if (e.e.button === 2 || !e.object.userData.type || !e.object.visible) return |
|||
|
|||
e.e.preventDefault() |
|||
|
|||
// 拖拽时禁用其他控制器
|
|||
this.viewport.controls.enabled = false |
|||
|
|||
this.isDragging = true |
|||
|
|||
// 记录拖拽按下的位置和对象
|
|||
this.onDownPosition = { x: e.e.clientX, y: e.e.clientY } |
|||
|
|||
// switch (e.object.userData.type) {
|
|||
// case 'measure-marker':
|
|||
// this.viewport.modules.measure.redraw(e.object)
|
|||
// break
|
|||
// }
|
|||
} |
|||
|
|||
// 拖拽中
|
|||
drag(e) { |
|||
this.viewport.dispatchSignal('objectChanged', e.object) |
|||
} |
|||
|
|||
// 拖拽结束
|
|||
dragControlsEnd(e) { |
|||
// 右键拖拽不响应
|
|||
if (e.e.button === 2 || !e.object.visible) return |
|||
|
|||
// 拖拽结束启用其他控制器
|
|||
this.viewport.controls.enabled = true |
|||
|
|||
this.isDragging = false |
|||
|
|||
if (!e.object.userData.type) return |
|||
|
|||
// 判断位置是否有变化,没有变化则为点击
|
|||
if (this.onDownPosition.x === e.e.clientX && this.onDownPosition.y === e.e.clientY) { |
|||
if (e.object.userData.onClick) { |
|||
e.object.userData.onClick(e) |
|||
} |
|||
} |
|||
|
|||
// switch (e.object.userData.type) {
|
|||
// case 'measure-marker':
|
|||
// this.viewport.modules.measure.redrawComplete()
|
|||
// break
|
|||
// }
|
|||
} |
|||
|
|||
// 点击可拖拽物体之外
|
|||
clickblank(e) { |
|||
if (e.e.button === 2) return |
|||
} |
|||
|
|||
dispose() { |
|||
this._dragObjects = [] |
|||
|
|||
this.dragControls.removeEventListener('dragstart', dragStartFn) |
|||
this.dragControls.removeEventListener('dragend', dragEndFn) |
|||
this.dragControls.dispose() |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
import type { ITool } from '@/designer/model2DEditor/tools/ITool.ts' |
|||
import Viewport from '@/designer/Viewport.ts' |
|||
|
|||
export default class RulerInspect implements ITool { |
|||
viewport: Viewport |
|||
|
|||
mouseMove(event: MouseEvent) { |
|||
const viewer = document.querySelector('.viewer') as HTMLElement |
|||
const rect = viewer.getBoundingClientRect() |
|||
|
|||
const mouseX = event.clientX - rect.left |
|||
const mouseY = event.clientY - rect.top |
|||
|
|||
console.log(`Mouse Position: (${mouseX}, ${mouseY})`) |
|||
} |
|||
|
|||
init(viewport: Viewport) { |
|||
this.viewport = viewport |
|||
const viewerDom = this.viewport.viewerDom |
|||
|
|||
system.msg('进入鼠标测距模式') |
|||
} |
|||
|
|||
destory(): void { |
|||
const viewerDom = this.viewport.viewerDom |
|||
viewerDom.removeEventListener('mousemove', this.mouseMove) |
|||
system.msg('退出鼠标测距模式') |
|||
} |
|||
} |
|||
@ -0,0 +1,318 @@ |
|||
import _ from 'lodash' |
|||
import PointPng from '@/assets/images/logo.png' |
|||
import * as THREE from 'three' |
|||
import type { ITool } from '@/designer/model2DEditor/tools/ITool.ts' |
|||
import Viewport from '@/designer/Viewport.ts' |
|||
import { numberToString, getUnitString } from '@/utils/webutils' |
|||
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer' |
|||
import { Vector3 } from 'three' |
|||
|
|||
let pdFn, pmFn, puFn, kdFn |
|||
|
|||
export default class RulerTool implements ITool { |
|||
static OBJ_NAME = 'object_for_measure' |
|||
static LABEL_NAME = 'label_for_measure' |
|||
static MAX_DISTANCE = 500 //当相交物体的距离太远时,忽略它
|
|||
|
|||
viewport: Viewport |
|||
// 当前测绘内容组
|
|||
group: THREE.Group |
|||
isCompleted = false |
|||
mouseMoved = false |
|||
canvas: HTMLCanvasElement |
|||
|
|||
// 用户在测量时绘制的线的当前实例
|
|||
protected polyline?: THREE.Line |
|||
|
|||
// 用于存储临时点
|
|||
protected tempPointMarker?: THREE.Mesh |
|||
|
|||
// 用于存储临时线条,用于在鼠标移动时绘制线条/区域/角度
|
|||
protected tempLine?: THREE.Line |
|||
|
|||
// 用于在鼠标移动时存储临时标签,只有测量距离时才有
|
|||
protected tempLabel?: CSS2DObject |
|||
|
|||
// 存储点
|
|||
protected pointArray: THREE.Vector3[] = [] |
|||
|
|||
//保存上次点击时间,以便检测双击事件
|
|||
protected lastClickTime: number = 0 |
|||
|
|||
|
|||
static LINE_MATERIAL = new THREE.LineBasicMaterial({ |
|||
color: 0xE63C17, |
|||
linewidth: 2, |
|||
opacity: 0.9, |
|||
transparent: true, |
|||
side: THREE.DoubleSide, |
|||
depthWrite: false, |
|||
depthTest: false |
|||
}) |
|||
|
|||
init(viewport: Viewport) { |
|||
this.viewport = viewport |
|||
const viewerDom = this.viewport.viewerDom |
|||
this.canvas = $(viewerDom).children('canvas')[0] as HTMLCanvasElement |
|||
|
|||
pdFn = this.mousedown.bind(this) |
|||
this.canvas.addEventListener('pointerdown', pdFn) |
|||
pmFn = this.mousemove.bind(this) |
|||
this.canvas.addEventListener('pointermove', pmFn) |
|||
puFn = this.mouseup.bind(this) |
|||
this.canvas.addEventListener('pointerup', puFn) |
|||
|
|||
// 初始化group
|
|||
this.group = new THREE.Group() |
|||
this.group.name = `${RulerTool.OBJ_NAME}_group` |
|||
this.group.userData = { |
|||
mode: this.viewport.state.cursorMode |
|||
} |
|||
this.viewport.scene.add(this.group) |
|||
|
|||
// 测量距离、面积和角度需要折线
|
|||
this.polyline = this.createLine() |
|||
this.group.add(this.polyline) |
|||
this.isCompleted = false |
|||
this.viewport.viewerDom.style.cursor = 'crosshair' |
|||
|
|||
// 当次绘制点
|
|||
this.pointArray = [] |
|||
|
|||
// 测量距离、面积和角度需要折线
|
|||
this.polyline = this.createLine() |
|||
this.group.add(this.polyline) |
|||
|
|||
this.viewport.viewerDom.style.cursor = 'crosshair' |
|||
|
|||
system.msg('进入鼠标测距模式') |
|||
} |
|||
|
|||
|
|||
destory(): void { |
|||
system.msg('退出鼠标测距模式') |
|||
|
|||
const viewerDom = this.viewport.viewerDom |
|||
|
|||
this.isCompleted = true |
|||
viewerDom.style.cursor = '' |
|||
|
|||
this.canvas.removeEventListener('pointerdown', pdFn) |
|||
pdFn = undefined |
|||
this.canvas.removeEventListener('pointermove', pmFn) |
|||
pmFn = undefined |
|||
this.canvas.removeEventListener('pointerup', puFn) |
|||
puFn = undefined |
|||
|
|||
this.tempPointMarker && this.viewport.scene.remove(this.tempPointMarker) |
|||
this.tempLine && this.viewport.scene.remove(this.tempLine) |
|||
this.tempLabel && this.viewport.scene.remove(this.tempLabel) |
|||
this.tempPointMarker = undefined |
|||
this.tempLine = undefined |
|||
this.tempLabel = undefined |
|||
} |
|||
|
|||
mousedown = () => { |
|||
this.mouseMoved = false |
|||
} |
|||
|
|||
|
|||
// 鼠标移动,创建对应的临时点与线
|
|||
mousemove = (e: MouseEvent) => { |
|||
if (this.isCompleted) return |
|||
|
|||
this.mouseMoved = true |
|||
|
|||
const point = this.getClosestIntersection(e) |
|||
if (!point) { |
|||
return |
|||
} |
|||
|
|||
// 在鼠标移动时绘制临时点
|
|||
if (this.tempPointMarker) { |
|||
this.tempPointMarker.position.set(point.x, point.y, point.z) |
|||
} else { |
|||
this.tempPointMarker = this.createPointMarker(point) |
|||
this.viewport.scene.add(this.tempPointMarker) |
|||
} |
|||
|
|||
// 移动时绘制临时线
|
|||
if (this.pointArray.length > 0) { |
|||
const p0 = this.pointArray[this.pointArray.length - 1] // 获取最后一个点
|
|||
const line = this.tempLine || this.createLine() |
|||
const geom = line.geometry |
|||
const startPoint = this.pointArray[0] |
|||
const lastPoint = this.pointArray[this.pointArray.length - 1] |
|||
if (this.viewport.state.cursorMode === 'RulerArea') { |
|||
geom.setFromPoints([lastPoint, point, startPoint]) |
|||
} else { |
|||
geom.setFromPoints([lastPoint, point]) |
|||
} |
|||
if (this.viewport.state.cursorMode === 'Ruler') { |
|||
const dist = p0.distanceTo(point) |
|||
const label = `${numberToString(dist)} ${getUnitString(this.viewport.state.cursorMode)}` |
|||
const position = new THREE.Vector3((point.x + p0.x) / 2, (point.y + p0.y) / 2, (point.z + p0.z) / 2) |
|||
this.addOrUpdateTempLabel(label, position) |
|||
} |
|||
// tempLine 只需添加到场景一次
|
|||
if (!this.tempLine) { |
|||
this.viewport.scene.add(line) |
|||
this.tempLine = line |
|||
} |
|||
} |
|||
|
|||
// this.viewport.dispatchSignal('sceneGraphChanged')
|
|||
} |
|||
|
|||
mouseup = (e: MouseEvent) => { |
|||
// 如果mouseMoved是true,那么它可能在移动,而不是点击
|
|||
if (!this.mouseMoved) { |
|||
// 右键点击表示完成绘图操作
|
|||
if (e.button === 2) { |
|||
this.viewport.state.cursorMode = 'normal' |
|||
|
|||
} else if (e.button === 0) { // 左键点击表示添加点
|
|||
this.onMouseClicked(e) |
|||
} |
|||
} |
|||
} |
|||
|
|||
onMouseClicked = (e: MouseEvent) => { |
|||
if (this.isCompleted) { |
|||
return |
|||
} |
|||
|
|||
const point = this.getClosestIntersection(e) |
|||
if (!point) { |
|||
return |
|||
} |
|||
|
|||
// 双击触发两次点击事件,我们需要避免这里的第二次点击
|
|||
const now = Date.now() |
|||
if (this.lastClickTime && (now - this.lastClickTime < 100)) return |
|||
|
|||
this.lastClickTime = now |
|||
|
|||
this.pointArray.push(point) |
|||
console.log('pointArray', this.pointArray) |
|||
|
|||
const count = this.pointArray.length |
|||
const marker = this.createPointMarker(point) |
|||
marker.userData.point = point |
|||
marker.userData.pointIndex = count - 1 |
|||
this.group.add(marker) |
|||
// 把点加入拖拽控制器
|
|||
this.viewport.dragControl.setDragObjects([marker], 'push') |
|||
|
|||
if (this.polyline) { |
|||
this.polyline.geometry.setFromPoints(this.pointArray) |
|||
if (this.tempLabel && count > 1) { |
|||
const p0 = this.pointArray[count - 2] |
|||
this.tempLabel.position.set((p0.x + point.x) / 2, (p0.y + point.y) / 2, (p0.z + point.z) / 2) |
|||
this.group.add(this.tempLabel) |
|||
|
|||
// 创建距离测量线时,此处的 临时label 将作为正式的使用,不在this.clearTemp()中清除,故置为undefined
|
|||
this.tempLabel = undefined |
|||
} |
|||
} |
|||
|
|||
// this.viewport.dispatchSignal('sceneGraphChanged')
|
|||
} |
|||
|
|||
/** |
|||
* Creates THREE.Line |
|||
*/ |
|||
private createLine(): THREE.Line { |
|||
const geom = new THREE.BufferGeometry() |
|||
const obj = new THREE.Line(geom, RulerTool.LINE_MATERIAL) |
|||
obj.frustumCulled = false |
|||
obj.name = RulerTool.OBJ_NAME |
|||
obj.userData = { |
|||
type: 'line' |
|||
} |
|||
return obj |
|||
} |
|||
|
|||
/** |
|||
* 创建点标记 |
|||
*/ |
|||
createPointMarker(position?: THREE.Vector3): THREE.Mesh { |
|||
const p = position |
|||
const scale = 0.25 |
|||
|
|||
const tt = new THREE.BoxGeometry(1, 1, 1) |
|||
const t2 = new THREE.MeshBasicMaterial({ color: 0x303133, transparent: true, opacity: 0.9 }) |
|||
const obj = new THREE.Mesh(tt, t2) |
|||
obj.scale.set(scale, 0.1, scale) |
|||
if (p) { |
|||
obj.position.set(p.x, p.y, p.z) |
|||
} |
|||
|
|||
obj.name = RulerTool.OBJ_NAME |
|||
|
|||
obj.userData = { |
|||
mode: this.viewport.state.cursorMode, |
|||
type: 'measure-marker' |
|||
} |
|||
return obj |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取按下对应三维位置 |
|||
*/ |
|||
getClosestIntersection(e: MouseEvent) { |
|||
const _point = new THREE.Vector2() |
|||
_point.x = e.offsetX / this.viewport.renderer.domElement.offsetWidth |
|||
_point.y = e.offsetY / this.viewport.renderer.domElement.offsetHeight |
|||
|
|||
const intersects = this.viewport.getIntersects(_point) |
|||
if (intersects && intersects.length > 2) { |
|||
if (intersects.length > 0 && intersects[0].distance < RulerTool.MAX_DISTANCE) { |
|||
return new Vector3( |
|||
intersects[0].point.x, |
|||
0.1, |
|||
intersects[1].point.z |
|||
) |
|||
} |
|||
} |
|||
return null |
|||
} |
|||
|
|||
/** |
|||
* 添加或更新临时标签和位置 |
|||
*/ |
|||
addOrUpdateTempLabel(label: string, position: THREE.Vector3) { |
|||
if (!this.tempLabel) { |
|||
this.tempLabel = this.createLabel(label) |
|||
this.viewport.scene.add(this.tempLabel) |
|||
} |
|||
this.tempLabel.position.set(position.x, position.y, position.z) |
|||
this.tempLabel.element.innerHTML = label |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 创建标签 |
|||
*/ |
|||
createLabel(text: string): CSS2DObject { |
|||
const div = document.createElement('div') |
|||
div.className = 'css2dObjectLabel' |
|||
div.innerHTML = text |
|||
div.style.padding = '5px 8px' |
|||
div.style.color = '#fff' |
|||
div.style.fontSize = '14px' |
|||
div.style.position = 'absolute' |
|||
div.style.backgroundColor = 'rgba(25, 25, 25, 0.3)' |
|||
div.style.borderRadius = '12px' |
|||
div.style.top = '0px' |
|||
div.style.left = '0px' |
|||
// div.style.pointerEvents = 'none' //避免HTML元素影响场景的鼠标事件
|
|||
const obj = new CSS2DObject(div) |
|||
obj.name = RulerTool.LABEL_NAME |
|||
obj.userData = { |
|||
type: 'label' |
|||
} |
|||
return obj |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
type CursorMode = |
|||
'normal' |
|||
| 'ALink' |
|||
| 'SLink' |
|||
| 'PointCallback' |
|||
| 'PointAdd' |
|||
| 'LinkAdd' |
|||
| 'LinkAdd2' |
|||
| 'Ruler' |
|||
| 'RulerArea' |
|||
| 'RulerAngle' |
|||
| 'selectByRec' |
|||
Loading…
Reference in new issue