class MarkerRenderByData { 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 = { } // 轨道帧数据 trackFrameMap = {} handler = {} currentFrameData = null; downloadImagesCount = 0 downloadingImagesCount = 0 downloadStartedAt = 0 // 相机 camera = null; scene = null; renderer = 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.fetchTrackData() this.createMarkers(50) } on(type, fn) { this.handler[type] = fn } fetchTrackData() { const vm = this vm.downloadStartedAt = new Date().getTime() this.config.tracks.forEach(track => { this.fetchFrameData(track) vm.downloadImagesCount += track.steps }) } fetchFrameData(track) { const vm = this axios.get(`${track.dataUrl}`).then(function(response) { const trackDatas = response.data console.log(response) vm.parseTrackData(track.name, trackDatas) vm.preDownloadImages(track.name) vm.changeTrack(null) }); } /** * 解析数据 * @param {*} trackName * @param {*} trackDatas */ parseTrackData(trackName, trackDatas) { const frames = {} const lines = trackDatas.split('\n') let currentIndex = 0; for (let index = 0; index < lines.length; index++) { const lineStr = lines[index] if (lineStr.indexOf('.jpg') > -1) { // 头 currentIndex = `frame-${lineStr.split('.')[0]}` frames[currentIndex] = [] } else { // 体 if (lineStr.length > 0) { // if(lineStr.length<4) return; // console.log(lineStr,lineStr.split('|')) // let temp=lineStr // temp=temp.split('|')[2].split(','); // temp[0]*=wdts; // temp[1]*=hets; // temp=temp.join(',') // console.log(lineStr.split('|')[2]) const originData = { name: lineStr.split('|')[0], originPosition: lineStr.split('|')[1], screenPosition: lineStr.split('|')[2], type: lineStr.split('|')[3] } frames[currentIndex].push(originData) } } } this.trackFrameMap[trackName] = frames } 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] this.currentFrameData = this.trackFrameMap[this.currentTrackData.name][`frame-${this.currentFrameStep}`] if (images) { const frame = images[this.currentFrameStep] if (frame) { console.log('url: ', frame.image.src) this.ctx.clearRect(0, 0, this.width, this.height) if (this.isClip) { const _clipX = this.clipX / 2 this.ctx.drawImage(frame.image, _clipX, 0, frame.image.width - _clipX * 2, frame.image.height, 0, 0, this.width + _clipX, this.height) } else { this.ctx.drawImage(frame.image, 0, 0, frame.image.width, frame.image.height, 0, 0, this.width, this.height) } this.updateMarkers(frame) } else { console.log('no frame data') } } else { console.log('no images') } } /** * 创建markers */ createMarkers(count) { for (let i = 0; i < count; i++) { const divEl = document.createElement('div') // divEl.className = 'marker-anmi' divEl.setAttribute('d-markerId', i) divEl.style.display = 'none' this.markerEls.push({ marker: null, 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-marker-name') fn(markerId) } } updateMarkers() { this.markerEls.forEach(markerItem => { markerItem.el.style.display = 'none' }) if (!this.currentFrameData) { return } const container = document.getElementById('render-container') console.log(container.offsetHeight) const rect = container.getBoundingClientRect() console.log(rect) let wdts = rect.width / 800, hets = rect.height / 540; // if (lineStr.split('|')[2]) { // // console.log(lineStr.split('|')[2].split(',')) // temp=temp.split('|')[2].split(','); // temp[0]*=wdts; // temp[1]*=hets; // temp=temp.join(',') // // console.log(lineStr.split('|')[2]) // } for (let i = 0; i < this.currentFrameData.length; i++) { const markerData = this.currentFrameData[i] const markerItem = this.markerEls[i] const photoWidth = this.config.globalMeta.photoSize[0] const photoHeight = this.config.globalMeta.photoSize[1] try { markerItem.el.setAttribute('d-marker-name', markerData.name) const markerTop = Number(markerData.screenPosition.split(',')[1]) const markerLeft = Number(markerData.screenPosition.split(',')[0]) const top = markerTop / photoHeight * this.height*hets console.log(top) let width = 0 if (this.isClip) { width = markerLeft / photoWidth * (this.width + this.clipX) - this.clipX / 4 } else { width = markerLeft / photoWidth * this.width } width*=wdts if ((markerTop >= 0 && markerTop <= photoHeight) && (markerLeft >= 0 && markerLeft <= photoWidth && width <= this.width)) { if (markerData.type.indexOf('camera') > -1) { markerItem.el.className = 'marker-anmi-camera' } if (markerData.type.indexOf('mic') > -1) { markerItem.el.className = 'marker-anmi-mic' } markerItem.el.style = 'block' markerItem.el.style.top = `${top+this.top}px` markerItem.el.style.left = `${width+this.left}px` } else { console.log('out of bounds') } } catch (error) { // console.error('update markers:', error) } } } 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(trackName) { // 总步数 if (this.trackImageMap[trackName]) { return } const vm = this const frameDatas = [] this.trackImageMap[trackName] = frameDatas const stepCount = this.currentTrackData.steps for (let i = 0; i < stepCount; i++) { const image = new Image() const frameData = this.getFrameData(trackName, i) image.onload = () => { vm.downloadingImagesCount++ frameDatas[i].image = image 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.renderFrameData() } } image.src = frameData.imageUrl frameDatas.push({ step: i, frameData: frameData }) } } /** * 获取帧数据 * 首先通过公式取,再以值修正 */ getFrameData(trackName, step) { const track = this.config.tracks.find(item => { return item.name === trackName }) let imageUrl = track.photoUrl imageUrl = imageUrl.replace('{prefixName}', track.prefixName) imageUrl = imageUrl.replace('{step}', step) const frame = this.trackFrameMap[track.name][`frame-${step}`] return { imageUrl: imageUrl, frame: frame } } changeTrack(type) { const lastTrackIndex = this.currentTrackIndex 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.currentTrackIndex !== lastTrackIndex) { if (this.config.tracks[this.currentTrackIndex]) { this.currentTrackData = this.config.tracks[this.currentTrackIndex] console.log('change track', this.currentTrackData) const fn = this.handler['trackChanged'] if (fn) { fn(this.currentTrackData.name) } setTimeout(() => { this.renderFrameData() }, 0); } } } 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 } }