123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- class MarkerRenderByPath {
- isClip = false;
- clipX = 0;
- container = null;
- config = null;
- lastPosition = null;
- ctx = null;
- width = 0;
- height = 0;
- top = 0;
- left = 0;
- markerEls = [];
- mouseDownStatus = false;
- // 当前轨道索引
- currentTrackIndex = 0;
- // 当前轨道配置数据
- currentTrackData = null;
- // 当前轨道路径
- currentTrackPath = null;
- // 当前角度,0-1 表示0-Math.PI*2
- currentAngle = 0;
- // 当前帧步
- currentFrameStep = 0;
- // 轨道下的图像数据
- trackImageMap = {
- }
- downloadImagesCount = 0
- downloadingImagesCount = 0
- downloadStartedAt = 0
- handler = {}
- // 相机
- camera = null;
- constructor(options){
- this.container = options.container
- this.container.style.cursor = 'grab'
- this.config = options.config
- this.isClip = options.isClip
- this.currentTrackData = this.config.tracks[0]
- this.generateEl()
- this.createMarkers()
- this.changeTrack(null)
- this.preDownloadImages()
- this.camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
- }
- on(type, fn){
- this.handler[type] = fn
- }
- generateEl(){
- const rect = this.container.getBoundingClientRect()
- const canvasEl = document.createElement('canvas')
- this.width = rect.width
- this.height = rect.height
- if(this.isClip){
- this.clipX = (this.config.globalMeta.photoSize[0] / this.config.globalMeta.photoSize[1]) * this.height - this.width
- }
- this.top = rect.top
- this.left = rect.left
- canvasEl.width = rect.width
- canvasEl.height = rect.height
- const ctx = canvasEl.getContext('2d')
- this.ctx = ctx;
- canvasEl.addEventListener('mousemove', this.mouseMoveHandler)
- canvasEl.addEventListener('mousedown', this.mouseDownHandler)
- canvasEl.addEventListener('mouseup', this.mouseUpHandler)
- this.container.appendChild(canvasEl)
- }
- /**
- * 获取当前轨道帧数据
- */
- renderFrameData(){
- const images = this.trackImageMap[this.currentTrackData.name]
- if(images){
- const frame = images[this.currentFrameStep]
- if(frame){
- this.ctx.clearRect(0,0,this.width,this.height)
- this.ctx.drawImage(frame.image, 0, 0, frame.image.width, frame.image.height, 0, 0, this.width, this.height)
- this.updateCamera(frame)
- this.updateMarkers(frame)
- }
- }
- }
- updateCamera(frame){
- const {camera} = this
- const _point = frame.frameData.cPoint
- const _target = frame.frameData.cTarget
- const cpoint = new THREE.Vector3(_point[0], _point[1], _point[2])
- camera.position.copy(cpoint)
- camera.lookAt(new THREE.Vector3(_target[0], _target[1], _target[2]))
- camera.updateMatrix()
- camera.updateMatrixWorld()
- camera.updateWorldMatrix()
- camera.updateProjectionMatrix()
- }
- /**
- * 创建markers
- */
- createMarkers(){
- this.config.markers.forEach(marker =>{
- const divEl = document.createElement('div')
- divEl.setAttribute('d-markerId', marker.id)
- marker._point = new THREE.Vector3(marker.position[0], marker.position[1], marker.position[2])
- this.markerEls.push({
- marker: marker,
- el: divEl
- })
- divEl.addEventListener('click', this.clickMarker)
- this.container.appendChild(divEl)
- })
- }
- clickMarker =(ev)=>{
- const fn = this.handler['markerClicked']
- if(fn){
- const markerId = ev.target.getAttribute('d-markerId')
- fn(markerId)
- }
- }
- updateMarkers(){
- this.markerEls.forEach(markerItem => {
- if(markerItem.marker.type.indexOf('camera')>-1){
- markerItem.el.className = 'marker-anmi-camera'
- }
- if(markerItem.marker.type.indexOf('mic')>-1){
- markerItem.el.className = 'marker-anmi-mic'
- }
- const sP = this.scenePositionToScreenLocation(new THREE.Vector3().copy(markerItem.marker._point))
- markerItem.el.style.top = `${sP.y}px`
- markerItem.el.style.left = `${sP.x}px`
- })
- }
- scenePositionToScreenLocation(position){
- const {camera, width, height} = this
- const centerX = width / 2
- const centerY = height / 2
- const ppv = position.project(camera)
- return {
- x: Math.round(centerX*ppv.x + centerX),
- y: Math.round(-centerY*ppv.y + centerY)
- }
- }
- /**
- * 预加载图片
- */
- preDownloadImages(){
- // 总步数
- if(this.trackImageMap[this.currentTrackData.name]){
- return
- }
- const vm = this
- this.config.tracks.forEach(track => {
- vm.downloadImagesCount += track.steps
- })
- this.config.tracks.forEach(track => {
- const frameDatas = []
- this.trackImageMap[track.name] = frameDatas
- const stepCount = track.steps
- for(let i=0;i<stepCount;i++){
- const image = new Image()
- const frameData = this.getFrameData(i / stepCount, track)
- image.onload = ()=>{
- vm.downloadingImagesCount++
- frameDatas.push({
- step: i,
- image: image,
- frameData: frameData
- })
- if(vm.downloadImagesCount === vm.downloadingImagesCount){
- const fn = this.handler['imagesDownloaded']
- if(fn){
- const at = new Date().getTime()
- fn(at - vm.downloadStartedAt)
- }
- console.log('downloadFinished')
- vm.changeTrack(null)
- vm.renderFrameData()
- }
- }
- image.src = frameData.imageUrl
- }
- })
- }
- /**
- * 获取帧数据
- * 首先通过公式取,再以值修正
- */
- getFrameData(step, track){
- // 首先通过公式取,再以值修正
- const fixData = track.stepParams.find(stepParamItem => {
- return Math.abs(stepParamItem.stepValue - step) < 0.05
- })
- let imageUrl = ''
- let cPoint = null
- let cTarget = null
- if(fixData){
- // 有修正数据,使用修正数据
- imageUrl = fixData.photoUrl,
- cTarget = fixData.target,
- cPoint = fixData.camera_position
- }else{
- // 使用轨道数据
- imageUrl = track.photoUrl.replace('{step}', step.toFixed(2))
- cTarget = track.target
- const cPath = new THREE.Path()
- cPath.absarc(track.origin[0], track.origin[1], track.radis)
- const point = cPath.getPointAt(Number(step))
- cPoint = [point.x, track.height, point.y]
- }
- return {
- cPoint: cPoint,
- imageUrl: imageUrl,
- cTarget: cTarget
- }
- }
- changeTrack(type){
- if(type === 'next'){
- // 切换下一个轨道
- this.currentTrackIndex++
- }
- if(type === 'prev'){
- // 切换上一个轨道
- this.currentTrackIndex--
- }
- if(this.currentTrackIndex > this.config.tracks.length){
- this.currentTrackIndex = this.config.tracks.length - 1
- }
- if(this.currentTrackIndex < 0){
- this.currentTrackIndex = 0
- }
- if(this.config.tracks[this.currentTrackIndex]){
- this.currentTrackData = this.config.tracks[this.currentTrackIndex]
- const cPath = new THREE.Path()
- cPath.absarc(this.currentTrackData.origin[0], this.currentTrackData.origin[1], this.currentTrackData.radis)
- this.currentTrackPath = cPath
- this.preDownloadImages()
- const fn = this.handler['trackChanged']
- if(fn){
- fn(this.currentTrackData.name)
- }
- this.renderFrameData()
- }
- }
-
- mouseMoveHandler = (ev)=>{
- if(this.mouseDownStatus){
- const diffX = ev.clientX - this.lastPosition.x
- const diffY = ev.clientY - this.lastPosition.y
- if(Math.abs(diffX) > Math.abs(diffY)){
- // 水平方向移动,触发图像更新
- if(Math.abs(diffX) > 10){
- // 阈值
- this.currentFrameStep += ev.clientX > this.lastPosition.x ? 1 : -1
- this.currentFrameStep = this.currentFrameStep%this.currentTrackData.steps
- if(this.currentFrameStep < 0){
- this.currentFrameStep = this.currentTrackData.steps + this.currentFrameStep
- }
- this.renderFrameData()
- this.lastPosition = {
- x: ev.clientX,
- y: ev.clientY
- }
- }
- }else{
- // 竖直方向移动,触发轨道切换
- if(Math.abs(diffY)>20){
- this.changeTrack(ev.clientY > this.lastPosition.y ? 'next' : 'prev')
- this.lastPosition = {
- x: ev.clientX,
- y: ev.clientY
- }
- }
- }
- }
- }
- mouseDownHandler = (ev)=>{
- this.mouseDownStatus = true
- this.lastPosition = {
- x: ev.clientX,
- y: ev.clientY
- }
- }
- mouseUpHandler = (ev)=>{
- this.mouseDownStatus = false
- }
- }
|