renderByData.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. class MarkerRenderByData {
  2. isClip = false;
  3. clipX = 0;
  4. container = null;
  5. config = null;
  6. lastPosition = null;
  7. ctx = null;
  8. width = 0;
  9. height = 0;
  10. top = 0;
  11. left = 0;
  12. markerEls = [];
  13. mouseDownStatus = false;
  14. // 当前轨道索引
  15. currentTrackIndex = 0;
  16. // 当前轨道配置数据
  17. currentTrackData = null;
  18. // 当前轨道路径
  19. currentTrackPath = null;
  20. // 当前角度,0-1 表示0-Math.PI*2
  21. currentAngle = 0;
  22. // 当前帧步
  23. currentFrameStep = 0;
  24. // 轨道下的图像数据
  25. trackImageMap = {
  26. }
  27. // 轨道帧数据
  28. trackFrameMap = {}
  29. handler = {}
  30. currentFrameData = null;
  31. downloadImagesCount = 0
  32. downloadingImagesCount = 0
  33. downloadStartedAt = 0
  34. // 相机
  35. camera = null;
  36. scene = null;
  37. renderer = null;
  38. constructor(options) {
  39. this.container = options.container
  40. this.container.style.cursor = 'grab'
  41. this.config = options.config
  42. this.isClip = options.isClip
  43. this.currentTrackData = this.config.tracks[0]
  44. this.generateEl()
  45. this.fetchTrackData()
  46. this.createMarkers(50)
  47. }
  48. on(type, fn) {
  49. this.handler[type] = fn
  50. }
  51. fetchTrackData() {
  52. const vm = this
  53. vm.downloadStartedAt = new Date().getTime()
  54. this.config.tracks.forEach(track => {
  55. this.fetchFrameData(track)
  56. vm.downloadImagesCount += track.steps
  57. })
  58. }
  59. fetchFrameData(track) {
  60. const vm = this
  61. axios.get(`${track.dataUrl}`).then(function(response) {
  62. const trackDatas = response.data
  63. console.log(response)
  64. vm.parseTrackData(track.name, trackDatas)
  65. vm.preDownloadImages(track.name)
  66. vm.changeTrack(null)
  67. });
  68. }
  69. /**
  70. * 解析数据
  71. * @param {*} trackName
  72. * @param {*} trackDatas
  73. */
  74. parseTrackData(trackName, trackDatas) {
  75. const frames = {}
  76. const lines = trackDatas.split('\n')
  77. let currentIndex = 0;
  78. for (let index = 0; index < lines.length; index++) {
  79. const lineStr = lines[index]
  80. if (lineStr.indexOf('.jpg') > -1) {
  81. // 头
  82. currentIndex = `frame-${lineStr.split('.')[0]}`
  83. frames[currentIndex] = []
  84. } else {
  85. // 体
  86. if (lineStr.length > 0) {
  87. // if(lineStr.length<4) return;
  88. // console.log(lineStr,lineStr.split('|'))
  89. // let temp=lineStr
  90. // temp=temp.split('|')[2].split(',');
  91. // temp[0]*=wdts;
  92. // temp[1]*=hets;
  93. // temp=temp.join(',')
  94. // console.log(lineStr.split('|')[2])
  95. const originData = {
  96. name: lineStr.split('|')[0],
  97. originPosition: lineStr.split('|')[1],
  98. screenPosition: lineStr.split('|')[2],
  99. type: lineStr.split('|')[3]
  100. }
  101. frames[currentIndex].push(originData)
  102. }
  103. }
  104. }
  105. this.trackFrameMap[trackName] = frames
  106. }
  107. generateEl() {
  108. const rect = this.container.getBoundingClientRect()
  109. const canvasEl = document.createElement('canvas')
  110. this.width = rect.width
  111. this.height = rect.height
  112. if (this.isClip) {
  113. this.clipX = (this.config.globalMeta.photoSize[0] / this.config.globalMeta.photoSize[1]) * this.height -
  114. this.width
  115. }
  116. this.top = rect.top
  117. this.left = rect.left
  118. canvasEl.width = rect.width
  119. canvasEl.height = rect.height
  120. const ctx = canvasEl.getContext('2d')
  121. this.ctx = ctx;
  122. canvasEl.addEventListener('mousemove', this.mouseMoveHandler)
  123. canvasEl.addEventListener('mousedown', this.mouseDownHandler)
  124. canvasEl.addEventListener('mouseup', this.mouseUpHandler)
  125. this.container.appendChild(canvasEl)
  126. }
  127. /**
  128. * 获取当前轨道帧数据
  129. */
  130. renderFrameData() {
  131. const images = this.trackImageMap[this.currentTrackData.name]
  132. this.currentFrameData = this.trackFrameMap[this.currentTrackData.name][`frame-${this.currentFrameStep}`]
  133. if (images) {
  134. const frame = images[this.currentFrameStep]
  135. if (frame) {
  136. console.log('url: ', frame.image.src)
  137. this.ctx.clearRect(0, 0, this.width, this.height)
  138. if (this.isClip) {
  139. const _clipX = this.clipX / 2
  140. this.ctx.drawImage(frame.image, _clipX, 0, frame.image.width - _clipX * 2, frame.image.height,
  141. 0, 0, this.width + _clipX, this.height)
  142. } else {
  143. this.ctx.drawImage(frame.image, 0, 0, frame.image.width, frame.image.height, 0, 0, this.width,
  144. this.height)
  145. }
  146. this.updateMarkers(frame)
  147. } else {
  148. console.log('no frame data')
  149. }
  150. } else {
  151. console.log('no images')
  152. }
  153. }
  154. /**
  155. * 创建markers
  156. */
  157. createMarkers(count) {
  158. for (let i = 0; i < count; i++) {
  159. const divEl = document.createElement('div')
  160. // divEl.className = 'marker-anmi'
  161. divEl.setAttribute('d-markerId', i)
  162. divEl.style.display = 'none'
  163. this.markerEls.push({
  164. marker: null,
  165. el: divEl
  166. })
  167. divEl.addEventListener('click', this.clickMarker)
  168. this.container.appendChild(divEl)
  169. }
  170. }
  171. clickMarker = (ev) => {
  172. const fn = this.handler['markerClicked']
  173. if (fn) {
  174. const markerId = ev.target.getAttribute('d-marker-name')
  175. fn(markerId)
  176. }
  177. }
  178. updateMarkers() {
  179. this.markerEls.forEach(markerItem => {
  180. markerItem.el.style.display = 'none'
  181. })
  182. if (!this.currentFrameData) {
  183. return
  184. }
  185. const container = document.getElementById('render-container')
  186. console.log(container.offsetHeight)
  187. const rect = container.getBoundingClientRect()
  188. console.log(rect)
  189. let wdts = rect.width / 800,
  190. hets = rect.height / 540;
  191. // if (lineStr.split('|')[2]) {
  192. // // console.log(lineStr.split('|')[2].split(','))
  193. // temp=temp.split('|')[2].split(',');
  194. // temp[0]*=wdts;
  195. // temp[1]*=hets;
  196. // temp=temp.join(',')
  197. // // console.log(lineStr.split('|')[2])
  198. // }
  199. for (let i = 0; i < this.currentFrameData.length; i++) {
  200. const markerData = this.currentFrameData[i]
  201. const markerItem = this.markerEls[i]
  202. const photoWidth = this.config.globalMeta.photoSize[0]
  203. const photoHeight = this.config.globalMeta.photoSize[1]
  204. try {
  205. markerItem.el.setAttribute('d-marker-name', markerData.name)
  206. const markerTop = Number(markerData.screenPosition.split(',')[1])
  207. const markerLeft = Number(markerData.screenPosition.split(',')[0])
  208. const top = markerTop / photoHeight * this.height*hets
  209. console.log(top)
  210. let width = 0
  211. if (this.isClip) {
  212. width = markerLeft / photoWidth * (this.width + this.clipX) - this.clipX / 4
  213. } else {
  214. width = markerLeft / photoWidth * this.width
  215. }
  216. width*=wdts
  217. if ((markerTop >= 0 && markerTop <= photoHeight) && (markerLeft >= 0 && markerLeft <= photoWidth &&
  218. width <= this.width)) {
  219. if (markerData.type.indexOf('camera') > -1) {
  220. markerItem.el.className = 'marker-anmi-camera'
  221. }
  222. if (markerData.type.indexOf('mic') > -1) {
  223. markerItem.el.className = 'marker-anmi-mic'
  224. }
  225. markerItem.el.style = 'block'
  226. markerItem.el.style.top = `${top+this.top}px`
  227. markerItem.el.style.left = `${width+this.left}px`
  228. } else {
  229. console.log('out of bounds')
  230. }
  231. } catch (error) {
  232. // console.error('update markers:', error)
  233. }
  234. }
  235. }
  236. scenePositionToScreenLocation(position) {
  237. const {
  238. camera,
  239. width,
  240. height
  241. } = this
  242. const centerX = width / 2
  243. const centerY = height / 2
  244. const ppv = position.project(camera)
  245. return {
  246. x: Math.round(centerX * ppv.x + centerX),
  247. y: Math.round(-centerY * ppv.y + centerY)
  248. }
  249. }
  250. /**
  251. * 预加载图片
  252. */
  253. preDownloadImages(trackName) {
  254. // 总步数
  255. if (this.trackImageMap[trackName]) {
  256. return
  257. }
  258. const vm = this
  259. const frameDatas = []
  260. this.trackImageMap[trackName] = frameDatas
  261. const stepCount = this.currentTrackData.steps
  262. for (let i = 0; i < stepCount; i++) {
  263. const image = new Image()
  264. const frameData = this.getFrameData(trackName, i)
  265. image.onload = () => {
  266. vm.downloadingImagesCount++
  267. frameDatas[i].image = image
  268. if (vm.downloadImagesCount === vm.downloadingImagesCount) {
  269. const fn = this.handler['imagesDownloaded']
  270. if (fn) {
  271. const at = new Date().getTime()
  272. fn(at - vm.downloadStartedAt)
  273. }
  274. console.log('downloadFinished')
  275. vm.renderFrameData()
  276. }
  277. }
  278. image.src = frameData.imageUrl
  279. frameDatas.push({
  280. step: i,
  281. frameData: frameData
  282. })
  283. }
  284. }
  285. /**
  286. * 获取帧数据
  287. * 首先通过公式取,再以值修正
  288. */
  289. getFrameData(trackName, step) {
  290. const track = this.config.tracks.find(item => {
  291. return item.name === trackName
  292. })
  293. let imageUrl = track.photoUrl
  294. imageUrl = imageUrl.replace('{prefixName}', track.prefixName)
  295. imageUrl = imageUrl.replace('{step}', step)
  296. const frame = this.trackFrameMap[track.name][`frame-${step}`]
  297. return {
  298. imageUrl: imageUrl,
  299. frame: frame
  300. }
  301. }
  302. changeTrack(type) {
  303. const lastTrackIndex = this.currentTrackIndex
  304. if (type === 'next') {
  305. // 切换下一个轨道
  306. this.currentTrackIndex++
  307. }
  308. if (type === 'prev') {
  309. // 切换上一个轨道
  310. this.currentTrackIndex--
  311. }
  312. if (this.currentTrackIndex > this.config.tracks.length) {
  313. this.currentTrackIndex = this.config.tracks.length - 1
  314. }
  315. if (this.currentTrackIndex < 0) {
  316. this.currentTrackIndex = 0
  317. }
  318. if (this.currentTrackIndex !== lastTrackIndex) {
  319. if (this.config.tracks[this.currentTrackIndex]) {
  320. this.currentTrackData = this.config.tracks[this.currentTrackIndex]
  321. console.log('change track', this.currentTrackData)
  322. const fn = this.handler['trackChanged']
  323. if (fn) {
  324. fn(this.currentTrackData.name)
  325. }
  326. setTimeout(() => {
  327. this.renderFrameData()
  328. }, 0);
  329. }
  330. }
  331. }
  332. mouseMoveHandler = (ev) => {
  333. if (this.mouseDownStatus) {
  334. const diffX = ev.clientX - this.lastPosition.x
  335. const diffY = ev.clientY - this.lastPosition.y
  336. if (Math.abs(diffX) > Math.abs(diffY)) {
  337. // 水平方向移动,触发图像更新
  338. if (Math.abs(diffX) > 10) {
  339. // 阈值
  340. this.currentFrameStep += ev.clientX > this.lastPosition.x ? 1 : -1
  341. this.currentFrameStep = this.currentFrameStep % this.currentTrackData.steps
  342. if (this.currentFrameStep < 0) {
  343. this.currentFrameStep = this.currentTrackData.steps + this.currentFrameStep
  344. }
  345. this.renderFrameData()
  346. this.lastPosition = {
  347. x: ev.clientX,
  348. y: ev.clientY
  349. }
  350. }
  351. } else {
  352. // 竖直方向移动,触发轨道切换
  353. if (Math.abs(diffY) > 20) {
  354. this.changeTrack(ev.clientY > this.lastPosition.y ? 'next' : 'prev')
  355. this.lastPosition = {
  356. x: ev.clientX,
  357. y: ev.clientY
  358. }
  359. }
  360. }
  361. }
  362. }
  363. mouseDownHandler = (ev) => {
  364. this.mouseDownStatus = true
  365. this.lastPosition = {
  366. x: ev.clientX,
  367. y: ev.clientY
  368. }
  369. }
  370. mouseUpHandler = (ev) => {
  371. this.mouseDownStatus = false
  372. }
  373. }