2 次代码提交 b106943522 ... 3c6f67afe3

作者 SHA1 备注 提交日期
  ldj 3c6f67afe3 update 1 年之前
  ldj c4f4c4c718 save 1 年之前

文件差异内容过多而无法显示
+ 3214 - 0
package-lock.json


+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "^2.1.0",
     "@element-plus/icons-vue": "^2.1.0",
     "@types/qs": "^6.9.7",
     "@types/qs": "^6.9.7",
+    "three": "^0.158.0",
     "axios": "^1.4.0",
     "axios": "^1.4.0",
     "echarts": "^5.4.3",
     "echarts": "^5.4.3",
     "element-plus": "^2.3.8",
     "element-plus": "^2.3.8",

+ 123 - 0
src/core/Scene.js

@@ -0,0 +1,123 @@
+import * as THREE from "three";
+import Stats from "three/examples/jsm/libs/stats.module.js";
+import Player from "./player/Player.js";
+import BoxManager from "./box/BoxManager.js";
+
+const stats = new Stats();
+
+export default class Scene {
+  constructor(domElement) {
+    this.domElement = domElement
+    this.scene = null
+    this.renderer = null
+    this.orthCamera = null
+    this.player = null
+
+    this.width = 0
+    this.height = 0
+    this.inited = false
+
+    this.init = () => {
+      this.scene = new THREE.Scene()
+      this.scene.background = new THREE.Color(0xf0f2f5)
+      this.renderer = new THREE.WebGLRenderer({canvas:this.domElement, antialias: true })
+
+      this.width = this.domElement.clientWidth
+      this.height = this.domElement.clientHeight
+      this.renderRes = window.devicePixelRatio
+
+      this.renderer.setSize(this.width, this.height)
+      this.renderer.setPixelRatio(this.renderRes)
+      console.log(this.width, this.height, this.renderRes)
+
+      this.orthCamera = new THREE.OrthographicCamera(
+        -this.width /2,
+        this.width /2,
+        this.height /2,
+        -this.height /2,
+        0.1,
+        1000
+      )
+      this.orthCamera.zoom = 250
+      this.orthCamera.updateProjectionMatrix();
+      this.orthCamera.position.set(0,10,0)
+      this.orthCamera.lookAt(0,0,0)
+
+      
+      //player
+      this.player = new Player(this)
+
+      //stats
+      domElement.parentNode.appendChild(stats.dom)
+      stats.dom.style.pointerEvents = 'none'
+      stats.dom.style.left = '15%'
+
+      this.onbindEvent()
+
+      this.inited = true
+      this.load()
+      this.animate()
+    }
+  }
+
+  load = (list) => {
+    if(!list) return
+    console.log('scene: ', list)
+    //axesHeloer
+    const axesHelper = new THREE.AxesHelper(1)
+    this.scene.add(axesHelper)
+
+
+    this.boxManager = new BoxManager(this)
+    this.boxManager.load(list)
+    //light
+    this.loadLight()
+  }
+
+  loadLight = () => {
+    const light = new THREE.AmbientLight(0xffffff, 1.5); // 柔和的白光
+    this.scene.add(light)
+  }
+
+  setCamera = () => {
+
+  }
+
+  toHorizontal = () => {
+
+  }
+  
+  toVertical = () => {
+    
+  }
+
+  onResize = (width, height) => {
+    this.width = width !== undefined ? width : this.domElement.clientWidth
+    this.height = height !== undefined ? height : this.domElement.clientHeight
+    console.log('resize', this.width, this.height)
+
+    this.orthCamera.left = -this.width /2,
+    this.orthCamera.right = this.width /2,
+    this.orthCamera.bottom = -this.height /2,
+    this.orthCamera.top = this.height /2,
+    this.orthCamera.updateProjectionMatrix()
+
+    this.renderer.setSize(this.width, this.height)
+  }
+  render = () => {
+    if(this.player) {
+      this.player.update()
+      this.renderer.render(this.scene, this.orthCamera);
+    }
+  }
+  animate = () => {
+    stats.begin();
+    this.render()
+    stats.end();
+    requestAnimationFrame(this.animate);
+  }
+
+  onbindEvent = () => {
+    //window.addEventListener('resize', this.onResize)
+  }
+}

+ 56 - 0
src/core/box/BoxManager.js

@@ -0,0 +1,56 @@
+import * as THREE from "three";
+import HorizontalBox from "./horizontalBox";
+
+
+export default class BoxManager {
+  constructor(scene) {
+    this.scene = scene
+    this.loadingManager = new THREE.LoadingManager()
+    this.loader = new THREE.TextureLoader( this.loadingManager )
+    this.model = new THREE.Group()
+    this.maps = {}
+    this.imgList = []
+    this.opacity = 1
+
+    this.onbindEvent()
+  }
+
+  load = (list) => {
+    list.forEach((item, index) => {
+      if( Array.isArray(item)) { //横排
+        const box = new HorizontalBox(this, item, index)
+        this.model.add(box)
+      } else {//竖排
+        
+      }
+    });
+
+    this.scene.scene.add(this.model)
+  }
+
+  onbindEvent = () => {
+    const _this = this
+    this.loadingManager.onStart = function(url, itemsLoaded, itemsTotal) {
+      // console.log( 'Started loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
+      console.log('loading_manager: loading...')
+    }
+    this.loadingManager.onLoad = function() {
+      console.log('loading_manager: loading complete!');
+    }
+    this.loadingManager.onProgress = function(url, itemsLoaded, itemsTotal) {
+      // console.log( 'Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
+    }
+    this.loadingManager.onError = function(url) {
+      console.error( 'loading_manager: error loading ' + url );
+    }
+  }
+
+  setVisible = (val) => {
+    if(!this.model) return
+    this.model.visible = val
+  }
+
+  setOpacity = (val) => {
+    this.material.opacity = val
+  }
+}

+ 65 - 0
src/core/box/HorizontalBox.js

@@ -0,0 +1,65 @@
+import * as THREE from "three";
+import TextLabel from "./object/TextLabel";
+import ImgLabel from "./object/ImgLabel";
+import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
+
+export default class HorizontalBox extends THREE.Group {
+  constructor(manager, data, index) {
+    super()
+    this.manager = manager
+    this.name = 'horizontal_box'
+    this.getStyle()
+    this.load(data, index)
+  }
+  getStyle() {
+    this.width = 2
+    this.height = 2 * 710/500 
+    this.color = 0xffffff
+  }
+
+  load(data, index) {
+    //box
+    const geometry = new THREE.PlaneGeometry(1,1)
+    geometry.rotateX(-Math.PI / 2)
+
+    const bm = new THREE.MeshBasicMaterial({
+      color: this.color
+    })
+
+    const box = new THREE.Mesh(geometry, bm)
+    box.scale.set(this.width, 1, this.height)
+
+    this.add(box)
+    this.position.x = (this.width + 0.125) * index
+
+
+    const matLine = new LineMaterial( {
+      color: 0x26559b,
+      linewidth: 3, // in world units with size attenuation, pixels otherwise
+      dashed: false,
+      alphaToCoverage: true,
+    });
+    matLine.resolution = new THREE.Vector2(this.manager.scene.width, this.manager.scene.height)
+    //content 
+    data.forEach((i, j) => {
+      //img
+      let img
+      this.manager.loader.load(i.imgUrl, (texture) => {
+        texture.colorSpace = THREE.SRGBColorSpace
+        img = new ImgLabel(texture, matLine)
+        img.position.y += 1
+        if(j === 0) {
+          img.position.z -= 0.8
+        } else {
+          img.position.z += 0.5
+        }
+        this.add(img)
+        this.manager.imgList.push(img)
+        const textlabel = new TextLabel(i.imgInfo, true)
+        this.add(textlabel)
+        textlabel.position.copy(img.position)
+        textlabel.position.z += textlabel.scale.z * 0.5 + 0.1
+      })
+    });
+  }
+}

+ 0 - 0
src/core/box/VerticalBox.js


+ 25 - 0
src/core/box/object/ImgLabel.js

@@ -0,0 +1,25 @@
+import * as THREE from "three";
+import TouchEdge from "./TouchEdge";
+
+export default class ImgLabel extends THREE.Mesh {
+  constructor(texture, matLine) {
+    const width = 1.5
+    const height = 0.85
+
+    const g = new THREE.PlaneGeometry(width, height)
+    g.rotateX(-Math.PI / 2)
+
+    const m = new THREE.MeshBasicMaterial({
+      map: texture
+    })
+    super(g,m)
+    console.log(g)
+    const p = [[-0.75, 0, -0.425, 0.75, 0, -0.425], [-0.75, 0, -0.425, -0.75, 0, 0.425], [-0.75, 0, 0.425, 0.75, 0, 0.425], [0.75, 0, 0.425, 0.75, 0, -0.425]]
+    this.touchLines = new TouchEdge(p, matLine)
+
+    this.touchLines.position.y += 0.5
+    this.add( this.touchLines );
+
+    this.name = 'imglabel'
+  }
+}

+ 39 - 0
src/core/box/object/Line.js

@@ -0,0 +1,39 @@
+import * as THREE from "three";
+import { Line2 } from 'three/examples/jsm/lines/Line2.js';
+import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
+
+const offset = 0.25
+
+function pointsToArray(arr) {
+  let res = []
+  arr.forEach(i => {
+    res = res.concat(i.toArray())
+  });
+  return res
+}
+export default class TouchEdge extends Line2 {
+  constructor(startPoint, endPoint, endEdge, matLine) {
+    let points;
+    // if(endEdge.name === 0) { //top
+      let a = startPoint.clone()
+      let b = new THREE.Vector3(startPoint.x, startPoint.y, endEdge.y - offset)
+      let c = new THREE.Vector3(endPoint.x, endPoint.y, endEdge.y - offset)
+      let d = new THREE.Vector3(endPoint.x, endPoint.y, endEdge.y)
+      points = pointsToArray([a,b,c,d])
+      console.log(points)
+    // } else if(endEdge.name === 1) { //left
+      
+    // } else if(endEdge.name === 2) { //bottom
+
+    // } else { //right
+
+    // }
+
+    const geometry = new LineGeometry();
+    geometry.setPositions(points);
+
+    super(geometry, matLine);
+    this.scale.set(1, 1, 1);
+    this.position.y += 0.5
+  }
+}

+ 46 - 0
src/core/box/object/TextLabel.js

@@ -0,0 +1,46 @@
+import * as THREE from "three";
+
+export default class TextLabel extends THREE.Mesh {
+  constructor(text, outline) {
+    let res = 5
+    const width = 150 * res
+    const height = 15 * res
+    var canvas = document.createElement('canvas');
+    canvas.width = width
+    canvas.height = height
+    let fontFamily = 'Arial'
+    let fontSize = 7 * res
+    let offsetX = 75 * res
+    let offsetY = 10 * res
+    var context = canvas.getContext('2d');
+
+    context.fillStyle = "#ffffff";
+    context.rect(0, 0, width, height);
+    context.fill()
+    context.font = 'normal ' + fontSize +"px " + fontFamily;
+    context.fillStyle = "#000000";
+    context.textAlign="center";
+    context.fillText(text,offsetX,offsetY);
+    const canvas_map = new THREE.Texture(canvas)
+    canvas_map.colorSpace = THREE.SRGBColorSpace
+    canvas_map.needsUpdate = true
+    canvas_map.anisotropy = 4
+
+    const g = new THREE.PlaneGeometry(1.5, 0.15)
+    g.rotateX(-Math.PI / 2)
+
+    const m = new THREE.MeshBasicMaterial({
+      map: canvas_map
+    })
+    super(g,m)
+
+    const edges = new THREE.EdgesGeometry( g );
+    const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xcccccc } ) );
+    line.position.y += 0.5
+    this.add( line );
+
+
+
+    this.name = 'textlabel_' + text
+  }
+}

+ 23 - 0
src/core/box/object/TouchEdge.js

@@ -0,0 +1,23 @@
+import * as THREE from "three";
+import { Line2 } from 'three/examples/jsm/lines/Line2.js';
+import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
+
+export default class TouchEdge extends THREE.Group {
+  constructor(positions, matLine) {
+    super()
+
+    positions.forEach((i, j) => { //top left bottom right
+      const geometry = new LineGeometry();
+      geometry.setPositions( i );
+
+      const line = new Line2( geometry, matLine );
+      line.scale.set( 1, 1, 1 );
+      line.position.y += 0.5
+      line.name = j
+      line.visible = false
+      line.x = i[0]
+      line.y = i[2]
+      this.add( line );
+    });
+  }
+}

+ 464 - 0
src/core/controls/FloorplanControls.js

@@ -0,0 +1,464 @@
+import {
+  Vector2,
+  Vector3
+} from "three";
+
+const STATE = {
+  NONE: - 1,
+  ROTATE: 0,
+  PAN: 1,
+  ZOOM: 2,
+  ZOOM_PAN: 3,
+  ZOOM_ROTATE: 4
+};
+const HANDLE =  {
+  ROTATE: 0,
+  PAN: 1,
+  ZOOM: 2,
+  ZOOM_PAN: 3,
+  ZOOM_ROTATE: 4
+}
+
+const pointers = []
+const pointerPositions = {}
+
+export default class FloorplanControls {
+  constructor(camera, dom, player){
+    this.camera = camera
+    this.domElement = dom
+    this.domElement.style.touchAction = 'none'; // disable touch scroll
+    this.player = player
+
+
+    this.panSpeed = 1
+    this.zoomSpeed = 1
+    this.rotateSpeed = 1
+
+    this.maxDistance = 100
+    this.minDistance = 0.1
+    this.maxZoom = 500
+    this.minZoom = 5
+
+    this.target = new Vector3()
+
+    this.state = STATE.NONE
+
+    this.rotateStart = new Vector2()
+    this.rotateEnd = new Vector2()
+
+    this.panStart = new Vector2()
+    this.panEnd = new Vector2()
+
+    this.zoomStart = new Vector2()
+
+    this.locked = false //禁止用户操作
+    this.enabled = true //禁止update
+    this.enablePan = true
+    this.enableRotate = true
+    this.enableZoom = true
+
+    this.touchesEvent = { 
+      ONE: HANDLE.PAN,
+      TWO: HANDLE.ZOOM 
+    }
+    this.mouseEvent = {
+      LEFT: HANDLE.PAN,
+      RIGHT: HANDLE.ROTATE,
+      WHEEL: HANDLE.ZOOM
+    }
+
+    this.onbindEvent()
+  }
+
+  onbindEvent = () => {
+    this.domElement.addEventListener('pointerdown', this.onPointerDown.bind(this))
+    this.domElement.addEventListener('pointerup', this.onPointerUp.bind(this))
+    this.domElement.addEventListener('pointermove', this.onPointerMove.bind(this))
+    this.domElement.addEventListener('pointercancel', this.onPointerUp.bind(this))
+    
+    this.domElement.addEventListener('mousewheel', this.onMouseWheel.bind(this), { passive: false })
+
+    this.domElement.addEventListener("contextmenu", this.onPreventDefault)
+  }
+  
+  addPointer = (event) => {
+    pointers.push(event);
+  }
+  removePointer = (event) => {
+    for ( let i = 0; i < pointers.length; i ++ ) {
+      if ( pointers[ i ].pointerId == event.pointerId ) {
+        pointers.splice( i, 1 );
+        return;
+      }
+    }
+  }
+  isTrackingPointer = (event) => {
+    for ( let i = 0; i < pointers.length; i ++ ) {
+      if ( pointers[ i ] == event.pointerId ) return true;
+    }
+    return false;
+  }
+  trackPointer = (event) => {
+    let position = pointerPositions[ event.pointerId ];
+    if ( position === undefined ) {
+      position = new Vector2();
+      pointerPositions[ event.pointerId ] = position;
+    }
+    position.set( event.pageX, event.pageY );
+  }
+  getSecondPointerPosition = (event) => {
+    const pointerId = ( event.pointerId === pointers[ 0 ].pointerId ) ? pointers[ 1 ].pointerId : pointers[ 0 ].pointerId;
+    return pointerPositions[ pointerId ];
+  }
+
+  // pointer event
+  onPointerDown = (event) => {
+    if(this.locked) return
+    if(pointers.length === 0) {
+      this.domElement.setPointerCapture( event.pointerId );
+    }
+    if(this.isTrackingPointer(event)) return;
+    this.addPointer(event)
+    if ( event.pointerType === 'touch' ) {
+      this.onTouchStart( event );
+    } else {
+      this.onMouseDown( event );
+    }
+  }
+  onPointerUp = (event) => {
+    if(this.locked) return
+    this.removePointer(event)
+    if(pointers.length === 0) {
+      this.domElement.releasePointerCapture( event.pointerId );
+      this.state = STATE.NONE
+    } else if (pointers.length === 1) {
+      const pointerId = pointers[ 0 ].pointerId;
+			const position = pointerPositions[ pointerId ];
+      this.onTouchStart( { pointerId: pointerId, pageX: position.x, pageY: position.y } );
+    }
+  }
+  onPointerMove = (event) => {
+    if(this.locked) return
+    if ( event.pointerType === 'touch' ) {
+      this.onTouchMove( event );
+    } else {
+      this.onMouseMove( event );
+    }
+  }
+
+  //touch event
+  onTouchStart = (event) => {
+    this.trackPointer(event)
+    switch(pointers.length) {
+      case 1:
+        switch(this.touchesEvent.ONE) {
+          case HANDLE.ROTATE: //rotate
+            if ( this.enableRotate === false ) return;
+            this.handleTouchStartRotate()
+            this.state = STATE.ROTATE
+            break
+          case HANDLE.PAN: //pan
+            if(this.enablePan === false) return;
+            this.handleTouchStartPan()
+            this.state = STATE.PAN
+            break
+          default:
+            state = STATE.NONE;
+        }
+        break
+      case 2:
+        switch (this.touchesEvent.TWO) {
+          case HANDLE.ZOOM: //zoom
+            if(this.enableZoom === false) return;
+            this.handleTouchStartZoom()
+            this.state = STATE.ZOOM
+            break
+          case HANDLE.ZOOM_PAN: //zoom_pan
+            if ( this.enableZoom === false && this.enablePan === false ) return;
+            this.handleTouchStartZoom()
+            this.handleTouchStartPan()
+            this.state = STATE.ZOOM_PAN
+            break
+            //todo case HANDLE.ZOOM_ROTATE:
+          default:
+            state = STATE.NONE;
+        }
+        break
+      default:
+        this.state = STATE.NONE
+    }
+  }
+  onTouchMove = (event) => {
+    this.trackPointer(event)
+    switch(this.state) {
+      case STATE.ROTATE:
+        if(this.enableRotate === false) return;
+        this.handleTouchMoveRotate(event)
+        break
+      case STATE.PAN:
+        if(this.enablePan === false) return;
+        this.handleTouchMovePan(event)
+        break
+      case STATE.ZOOM:
+        if(this.enableZoom === false) return;
+        this.handleTouchMoveZoom(event)
+        break
+      case STATE.ZOOM_PAN:
+        if(this.enableZoom) this.handleTouchMoveZoom(event)
+        if(this.enablePan) this.handleTouchMovePan(event)
+        break
+      //todo case STATE.ZOOM_ROTATE:
+      default:
+        this.state = STATE.NONE;
+    }
+  } 
+
+  //mouse event
+  onMouseDown = (event) => {
+    if(this.locked) return
+    switch(event.button) {
+      case 0: //left
+        switch(this.mouseEvent.LEFT) {
+          case HANDLE.PAN:
+            if(this.enablePan === false) return
+            this.handleMouseDownPan(event)
+            this.state = STATE.PAN
+            break
+          case HANDLE.ROTATE:
+              if(this.enablePan === false) return
+              this.handleMouseDownRotate(event)
+              this.state = STATE.ROTATE
+              break
+          default:
+            this.state = STATE.NONE
+        }
+        break
+      case 2: //right
+      switch(this.mouseEvent.RIGHT) {
+        case HANDLE.PAN:
+          if(this.enablePan === false) return
+          this.handleMouseDownPan(event)
+          this.state = STATE.PAN
+          break
+        case HANDLE.ROTATE:
+            if(this.enablePan === false) return
+            this.handleMouseDownRotate(event)
+            this.state = STATE.ROTATE
+            break
+        default:
+          this.state = STATE.NONE
+      }
+        break
+      default:
+        this.state = STATE.NONE
+    }
+  }
+  onMouseMove = (event) => {
+    if(this.locked) return
+    switch(this.state) {
+      case STATE.PAN:
+        if(this.enablePan === false) return
+        this.handleMouseMovePan(event)
+        break
+      case STATE.ROTATE:
+        if(this.enableRotate === false) return
+        this.handleMouseMoveRotate(event)
+        break
+      default:
+        this.state = STATE.NONE
+    }
+  }
+  onMouseWheel = (event) => {
+    if(this.locked) return
+    if(this.enableZoom === false) return
+    event.preventDefault()
+    this.handleMouseWheelZoom(event)
+  }
+  onPreventDefault = (event) => {
+    event.preventDefault()
+  }
+
+  //================================handle================================
+  //-------------------------rotate-------------------------
+  handleTouchStartRotate = () => {
+    const position = pointerPositions[pointers[ 0 ].pointerId]
+    this.rotateStart.set(position.x, position.y)
+  }
+  handleTouchMoveRotate = (event) => {
+    this.rotateEnd.set( event.pageX, event.pageY );
+    let rotateDelta = this.rotateEnd.clone().sub(  this.rotateStart ).multiplyScalar( this.rotateSpeed );
+    let element = this.domElement
+    let rotateX = 2 * Math.PI * rotateDelta.x / element.clientHeight
+    let rotateY = 2 * Math.PI * rotateDelta.y / element.clientHeight
+
+    this.rotate(rotateX, rotateY)
+
+    this.rotateStart.copy( this.rotateEnd );
+  }
+  handleMouseDownRotate = (event) => {
+    this.rotateStart.set(event.pageX, event.pageY)
+  }
+  handleMouseMoveRotate = (event) => {
+    this.rotateEnd.set( event.pageX, event.pageY );
+    let rotateDelta = this.rotateEnd.clone().sub(  this.rotateStart ).multiplyScalar( this.rotateSpeed );
+    let element = this.domElement
+    let rotateX = 2 * Math.PI * rotateDelta.x / element.clientHeight
+    let rotateY = 2 * Math.PI * rotateDelta.y / element.clientHeight
+
+    this.rotate(rotateX, rotateY)
+
+    this.rotateStart.copy( this.rotateEnd );
+  }
+  //-------------------------zoom-------------------------
+  handleTouchStartZoom = () => {
+    const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX;
+		const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY;
+    const distance = Math.sqrt( dx * dx + dy * dy );
+    this.zoomStart.set(0, distance)
+  }
+  handleTouchMoveZoom = (event) => {
+    const position = this.getSecondPointerPosition( event );
+    const dx = event.pageX - position.x;
+    const dy = event.pageY - position.y;
+    const distance = Math.sqrt( dx * dx + dy * dy );
+    let delta = Math.pow( distance / this.zoomStart.y, this.zoomSpeed )
+
+    this.zoom(1/delta)
+
+    this.zoomStart.set(0, distance)
+  }
+  handleMouseWheelZoom = (event) => {
+    if(event.deltaY > 0) { //zoom out
+      this.zoom(1.05 * this.zoomSpeed)
+    } else { //zoom in
+      this.zoom(0.95 * this.zoomSpeed)
+    }
+  }
+  //-------------------------pan-------------------------
+  handleTouchStartPan = () => {
+    if ( pointers.length === 1 ) {
+      const position = pointerPositions[pointers[ 0 ].pointerId]
+      this.panStart.set(position.x, position.y)
+    } else {
+      const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX );
+      const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY );
+      this.panStart.set( x, y );
+    }
+  }
+  handleTouchMovePan = (event) => {
+    if ( pointers.length === 1 ) {
+      this.panEnd.set( event.pageX, event.pageY );
+    } else {
+      const position = this.getSecondPointerPosition( event );
+      const x = 0.5 * ( event.pageX + position.x );
+      const y = 0.5 * ( event.pageY + position.y );
+      this.panEnd.set(x, y);
+    }
+    let panDelta = this.panEnd.clone().sub(this.panStart)
+
+    this.pan(panDelta)
+
+    this.panStart.copy(this.panEnd);
+  }
+  handleMouseDownPan = (event) => {
+    this.panStart.set(event.pageX, event.pageY)
+  } 
+  handleMouseMovePan = (event) => {
+    this.panEnd.set(event.pageX, event.pageY);
+    let panDelta = this.panEnd.clone().sub(this.panStart)
+
+    this.pan(panDelta)
+
+    this.panStart.copy(this.panEnd);
+  }
+
+  rotate(x, y) {
+    let r = y
+    if(Math.abs(x) > Math.abs(y)) r = x
+
+    let cameraRZ = this.camera.rotation.z
+    cameraRZ += r
+    if(Math.abs(cameraRZ) >= Math.PI * 2) {
+      cameraRZ -= Math.sign(cameraRZ) * Math.PI * 2
+    }
+    this.camera.rotation.z = cameraRZ
+    this.cameraUpate()
+  }
+  zoom(delta) {
+    // if(this.camera.isPerspectiveCamera) {
+    //   let cameraY = this.camera.position.y
+    //   cameraY *= delta
+    //   cameraY = Math.max(cameraY, this.minDistance)
+    //   cameraY = Math.min(cameraY, this.maxDistance)
+    //   this.camera.position.y = cameraY //handle
+    // } else if(this.camera.isOrthographicCamera) {
+    //   let zoom = this.camera.zoom
+    //   zoom *= 1/delta
+    //   console.log(zoom)
+    //   this.camera.zoom = zoom
+    //   this.camera.updateProjectionMatrix()
+    // }
+
+      let cameraY = this.camera.position.y
+      cameraY *= delta
+      cameraY = Math.max(cameraY, this.minDistance)
+      cameraY = Math.min(cameraY, this.maxDistance)
+      this.camera.position.y = cameraY //handle
+    if(this.camera.isOrthographicCamera) {
+      let zoom = this.camera.zoom
+      zoom *= 1/delta
+      zoom = Math.max(zoom, this.minZoom)
+      zoom = Math.min(zoom, this.maxZoom)
+      this.camera.zoom = zoom
+      this.camera.updateProjectionMatrix()
+    }
+
+    this.cameraUpate()
+  }
+  pan(delta) {
+    const element = this.domElement;
+    const matrix = this.camera.matrix.clone()
+    const left = new Vector3()
+    const up = new Vector3()
+    let panDelta = delta.multiplyScalar(this.panSpeed);
+
+    if(this.camera.isPerspectiveCamera ) {
+      let scalar = 2 * this.camera.position.y * Math.tan( ( this.camera.fov / 2 ) * Math.PI / 180.0 ) / element.clientHeight;
+      panDelta.multiplyScalar(scalar)
+
+      left.setFromMatrixColumn( matrix, 0 );
+      left.multiplyScalar( -panDelta.x );
+      up.setFromMatrixColumn( matrix, 1 );
+      up.multiplyScalar( panDelta.y );
+    } else if(this.camera.isOrthographicCamera){
+        panDelta.x = panDelta.x * ( this.camera.right - this.camera.left ) / this.camera.zoom / element.clientWidth, this.camera.matrix
+        panDelta.y = panDelta.y * ( this.camera.top - this.camera.bottom ) / this.camera.zoom / element.clientHeight, this.camera.matrix
+        left.setFromMatrixColumn( matrix, 0 );
+        left.multiplyScalar( -panDelta.x );
+        up.setFromMatrixColumn( matrix, 1 );
+        up.multiplyScalar( panDelta.y );
+    } else {
+      return
+    }
+    this.camera.position.add(left).add(up)
+    this.target.set(this.camera.position.x, 0, this.camera.position.z)
+    this.cameraUpate()
+  }
+
+  lookAt(target, height) {
+    if(!target) return
+    height = height !== undefined ? height : this.camera.position.y
+    this.camera.position.set(target.x, height, target.z)
+    this.target.set(target.x, 0, target.z)
+    this.camera.lookAt(this.target)
+  }
+
+  cameraUpate = () => {
+    this.camera.updateMatrix()
+    this.camera.updateProjectionMatrix()
+  }
+
+  update = () => {
+    if(!this.enabled) return
+  }
+}

+ 154 - 0
src/core/player/Player.js

@@ -0,0 +1,154 @@
+import * as THREE from "three";
+
+// import FloorplanControls from "../controls/FloorplanControls.js";
+import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+import Line from '../box/object/Line'
+import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
+
+
+const convertScreenToNDC =  function (event, domElement) {
+  let x = ( (event.offsetX) / domElement.clientWidth ) * 2 - 1;
+  let y = - ( (event.offsetY) / domElement.clientHeight ) * 2 + 1;
+  return new THREE.Vector2(x, y)
+}
+export default class Player {
+  constructor(scene) {
+    this.scene = scene
+    this.orthCamera = scene.orthCamera
+
+    this.floorplanControls = null
+    this.raycaster = null
+
+    this.position = new THREE.Vector3()
+
+    this.pointerdown = new THREE.Vector2()
+    this.pointerup = new THREE.Vector2()
+    this.pointer = new THREE.Vector2()
+
+    this.touchImg = null
+    this.activeEdge = null
+    this.drawLine = null
+
+
+    this.drawing = false
+    this.inited = false
+    this.init()
+  }
+
+  init = () => {
+    // //floorplanControls
+    // this.floorplanControls = new FloorplanControls(this.orthCamera, this.scene.domElement, this);
+    this.floorplanControls = new OrbitControls(this.orthCamera, this.scene.domElement);
+
+    // this.floorplanControls.target.set(0,0,0)
+    // this.floorplanControls.rotateSpeed = 0.5
+    // this.floorplanControls.panSpeed = 0.75
+    // this.floorplanControls.maxDistance = 100
+    // this.floorplanControls.minDistance = 3.5
+    // this.floorplanControls.maxZoom = 500
+    // this.floorplanControls.minZoom = 1
+
+    this.floorplanControls.enableRotate = false
+
+    this.raycaster = new THREE.Raycaster()
+
+    this.onbindEvent()
+    this.inited = true
+  }
+
+  onPointerMove = (e) => {
+    if(!this.drawing) return
+    this.pointermove = convertScreenToNDC(e, this.scene.domElement)
+    this.raycaster.setFromCamera( this.pointermove, this.orthCamera );
+    let intersectArr = this.scene.boxManager.imgList
+    const intersects = this.raycaster.intersectObjects( intersectArr, false );
+    if(intersects[0]) {
+      this.touchImg = intersects[0]
+      this.setActiveLine(this.touchImg)
+    }
+  }
+  onPointerDown = (e) => {
+    this.pointerdown = convertScreenToNDC(e, this.scene.domElement)
+    this.drawing = true
+    this.floorplanControls.enabled = false
+  }
+  onPointerUp = (e) => {
+    this.pointerup = convertScreenToNDC(e, this.scene.domElement)
+    this.drawing = false
+    this.floorplanControls.enabled = true
+  }
+
+  Listener = {
+    onPointerDown: this.onPointerDown.bind(this),
+    onPointerMove: this.onPointerMove.bind(this),
+    onPointerUp: this.onPointerUp.bind(this)
+  }
+
+  onbindEvent = () => {
+    this.scene.domElement.addEventListener('pointerdown', this.Listener.onPointerDown)
+    this.scene.domElement.addEventListener('pointermove', this.Listener.onPointerMove)
+    this.scene.domElement.addEventListener('pointerup', this.Listener.onPointerUp)
+  }
+  unbindEvent = () => {
+    this.scene.domElement.removeEventListener('pointerdown', this.Listener.onPointerDown)
+    this.scene.domElement.removeEventListener('pointermove', this.Listener.onPointerMove)
+    this.scene.domElement.removeEventListener('pointerup', this.Listener.onPointerUp)
+  }
+
+  buildLine = () => {
+    if(this.drawLine) {
+      this.drawLine.removeFromParent()
+    }
+    let s = new THREE.Vector3(this.pointerdown.x, this.pointerdown.y, -1)
+    let e = new THREE.Vector3(this.pointermove.x, this.pointermove.y, -1)
+    s.unproject(this.orthCamera)
+    e.unproject(this.orthCamera)
+    s.y = 5
+    e.y = 5
+    // console.log(s)
+
+    const matLine = new LineMaterial( {
+      color: 0x26559b,
+      linewidth: 3, // in world units with size attenuation, pixels otherwise
+      dashed: false,
+      alphaToCoverage: true,
+    });
+    matLine.resolution = new THREE.Vector2(this.scene.width, this.scene.height)
+    this.drawLine = new Line(s,e,this.activeEdge,matLine)
+    this.scene.scene.add(this.drawLine)
+  }
+
+  setActiveLine = (obj) => {
+    function getTouchLine(x, y) {
+      if(x >= 0.5 && y >= 0.5) {
+        if(x > y) {
+          return 3
+        } else {
+          return 0
+        }
+      } else {
+        if(x < y) {
+          return 1
+        } else {
+          return 2
+        }
+      }
+    }
+
+    if(this.activeEdge) {
+      this.activeEdge.visible = false
+      this.activeEdge = null
+    }
+
+    let num = getTouchLine(obj.uv.x, obj.uv.y)
+    this.activeEdge = obj.object.touchLines.getObjectByName(num)
+    this.activeEdge.visible = true
+    this.buildLine()
+  }
+
+  update = () => {
+    if(this.floorplanControls.enabled) {
+      this.floorplanControls && this.floorplanControls.update()
+    }
+  }
+}

+ 0 - 0
src/core/settings/style.js


+ 25 - 4
src/view/case/photos/index.vue

@@ -13,7 +13,7 @@
       <draggable ref="childRef" :caseId="caseId" :sortType="sortType" @changeList="changeList" @handleItem="handleItem" />
       <draggable ref="childRef" :caseId="caseId" :sortType="sortType" @changeList="changeList" @handleItem="handleItem" />
     </div>
     </div>
     <div class="right">
     <div class="right">
-      <swiper
+      <!-- <swiper
         class="swiper"
         class="swiper"
         slides-per-view="auto"
         slides-per-view="auto"
         :space-between="24"
         :space-between="24"
@@ -43,18 +43,20 @@
             </div>
             </div>
           </div>
           </div>
         </swiper-slide>
         </swiper-slide>
-      </swiper>
+      </swiper> -->
+      <canvas id="canvas"></canvas>
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { ref } from "vue";
+import { onMounted, ref } from "vue";
 import { Menu, FullScreen } from "@element-plus/icons-vue";
 import { Menu, FullScreen } from "@element-plus/icons-vue";
 import { Swiper, SwiperSlide } from "swiper/vue";
 import { Swiper, SwiperSlide } from "swiper/vue";
 import "swiper/css";
 import "swiper/css";
 // import { addCaseFile } from "@/store/caseFile";
 // import { addCaseFile } from "@/store/caseFile";
 import { addCaseImgFile } from "../quisk";
 import { addCaseImgFile } from "../quisk";
+import Scene from '@/core/Scene.js'
 import draggable from './draggable.vue';
 import draggable from './draggable.vue';
 const props = defineProps({ caseId: Number });
 const props = defineProps({ caseId: Number });
 const newlist = ref([]);
 const newlist = ref([]);
@@ -62,6 +64,7 @@ const swiperRef = ref(null);
 const childRef = ref(null);
 const childRef = ref(null);
 const caseId = ref(props.caseId);
 const caseId = ref(props.caseId);
 const sortType = ref(false);
 const sortType = ref(false);
+let scene = null;
 const addCaseFileHandler = async () => {
 const addCaseFileHandler = async () => {
   await addCaseImgFile({ caseId: caseId.value, data: {
   await addCaseImgFile({ caseId: caseId.value, data: {
     imgUrl: '',
     imgUrl: '',
@@ -90,9 +93,20 @@ const changeList = (list) => {
     }
     }
   });
   });
   newlist.value = newList;
   newlist.value = newList;
-  console.log("changeList", newList);
+  const arr = []
+  newList.map(i => arr.push(JSON.parse(JSON.stringify(i))))
+  if(scene) scene.load(arr)
+  console.log("changeList", arr);
 };
 };
+const renderCanvas = () => {
+  const canvas = document.getElementById('canvas')
+  console.log(canvas)
+  scene = new Scene(canvas)
+  scene.init()
+  window.scene = scene
+}
 const onSwiper = (swiper) => {
 const onSwiper = (swiper) => {
+  console.log('onSwiper')
   swiperRef.value = swiper;
   swiperRef.value = swiper;
 };
 };
 const onSlideChange = (swiper) => {
 const onSlideChange = (swiper) => {
@@ -110,8 +124,15 @@ const handleDetele = async (item) => {
     refresh();
     refresh();
   }
   }
 };
 };
+onMounted(() => {
+  renderCanvas();
+})
 </script>
 </script>
 <style lang="scss" scoped>
 <style lang="scss" scoped>
+#canvas {
+    width: 100%;
+    height: 100%;
+}
 .photo {
 .photo {
   display: flex;
   display: flex;
   height: 100%;
   height: 100%;

文件差异内容过多而无法显示
+ 752 - 862
yarn.lock