TileDownloader.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. import {TileDownloaderEvents, DownloadStatus} from '../../../defines'
  2. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  3. import TilePrioritizer from './TilePrioritizer'
  4. import TileUtils from './TileUtils'
  5. import {settings, config} from '../../../settings'
  6. import {
  7. http
  8. } from '../../../utils/request'
  9. import { EventDispatcher } from "../../../EventDispatcher.js";
  10. window.downloaded = {}
  11. window.startdownloads = [];
  12. class TileDownloader extends EventDispatcher{
  13. constructor( ) {
  14. super()
  15. this.panos = null;
  16. this.retryMinimumTime = 1e4;
  17. this.panoLoadCallbacks = {};
  18. this.downloadDescriptors = {};
  19. this.priorityQueue = [];
  20. this.forceQueue = [];
  21. this.activeDownloads = [];
  22. this.tilePrioritizer = null;
  23. this.refreshInterval = null;
  24. this.processPriorityQueue = !1;
  25. this.concurrentDownloads = 6;//e.concurrentDownloads || 1;
  26. this.downloadTestResults = {};
  27. this.freeze = Object.freeze({
  28. Testing: 1,
  29. Success: 2,
  30. Fail: 3
  31. });
  32. this.visible = true //add 借用viewer.updateVisible来判断是否start
  33. viewer.on('pageVisible', (state)=>{//不可见时不refreshUpdateInterval
  34. //console.log('visibilitychange:', state)
  35. viewer.updateVisible(this, 'pageVisible', state)
  36. this.judgeStart()
  37. })
  38. }
  39. setPanoData(e, t /* , i */) {
  40. this.panos = e,
  41. this.imagePanos = t
  42. // this.panoGroupId = i
  43. }
  44. start() {
  45. viewer.updateVisible(this,'pano', true )
  46. this.judgeStart()
  47. }
  48. stop() {
  49. viewer.updateVisible(this,'pano', false )
  50. this.judgeStart()
  51. }
  52. judgeStart(){//add
  53. if(this.visible){
  54. //console.log('judgeStart true')
  55. this.started = true
  56. this.refreshUpdateInterval(0)
  57. }else{
  58. //console.log('judgeStart false')
  59. this.started = false
  60. window.clearTimeout(this.refreshInterval)
  61. }
  62. }
  63. refreshUpdateInterval(e) {
  64. e || (e = 0),
  65. this.refreshInterval = window.setTimeout(function() {
  66. var e = this.update();
  67. e ? this.refreshUpdateInterval(TileDownloader.ACTIVE_REFRESH_DELAY) : this.refreshUpdateInterval(TileDownloader.IDLE_REFRESH_DELAY)
  68. }
  69. .bind(this), e)
  70. }
  71. update() {
  72. var e = this.forceQueue.length > 0;
  73. this.processQueueForDownloading(this.forceQueue);
  74. if (this.processPriorityQueue) {
  75. this.queuePrioritizedTilesForPanos(this.panos);
  76. this.priorityQueue.length > 0 && (e = !0);
  77. this.processQueueForDownloading(this.priorityQueue);
  78. }
  79. return e
  80. }
  81. queuePrioritizedTilesForPanos(e) {
  82. this.tilePrioritizer && (this.clearQueue(this.priorityQueue),
  83. this.tilePrioritizer.filterAndPrioritize(this.priorityQueue, e, this),
  84. this.clearFromQueue(this.priorityQueue, DownloadStatus.None, !0), //去除state为DownloadStatus.None的(可能是去除已经在下载的)
  85. this.setStatusOrRemoveForAllDescriptors(this.priorityQueue, DownloadStatus.Queued))
  86. }
  87. clearQueue(e) {//停止下载并清空
  88. this.setStatusForAllDescriptors(e, DownloadStatus.None),
  89. e.length = 0
  90. }
  91. clearForceQueue() {
  92. this.clearQueue(this.forceQueue)
  93. }
  94. clearFromQueue(e, t, i) {
  95. for (var n = 0; n < e.length; n++) {
  96. var r = e[n];
  97. r && (t === r.status && !i || t !== r.status && i) && (e[n] = null)
  98. }
  99. }
  100. setStatusForAllDescriptors(e, t) {
  101. for (var i = 0; i < e.length; i++) {
  102. var n = e[i];
  103. n && (n.status = t)
  104. }
  105. }
  106. setStatusOrRemoveForAllDescriptors(e, t) {
  107. for (var i = 0; i < e.length; i++) {
  108. var n = e[i];
  109. n && (n.status !== t ? n.status = t : e[i] = null)
  110. }
  111. }
  112. getTileDownloadDescriptors(pano, size) {//获取该pano的该size的全部的tile的descriptor
  113. var i = this.getAllTileDownloadDescriptorsForPano(pano),
  114. n = i[size];
  115. return n || (n = this.buildDownloadDescriptorArray(size),//创建的全部是空的
  116. i[size] = n,
  117. this.initTileDownloadDescriptors(n, pano, size)),//绑定到该pano size
  118. n
  119. }
  120. getAllTileDownloadDescriptorsForPano(pano) {//新建空Descriptors
  121. var t = this.downloadDescriptors[pano.id];
  122. return t || (t = {},
  123. this.downloadDescriptors[pano.id] = t),
  124. t
  125. }
  126. processQueueForDownloading(e, t) {//执行下载任务
  127. this.cleanupActiveDownloads();
  128. if (this.activeDownloads.length < this.concurrentDownloads || t) {
  129. var i = t ? e.length : this.concurrentDownloads - this.activeDownloads.length;
  130. for (var n = 0, r = 0; n < i && e.length > 0; r++) {
  131. var o = e.shift();
  132. if(o){
  133. //add 为了防止1024的在512前下载完,这里强行等待512下载完毕再开始下载
  134. if(o.panoSize > 512 && !this.isPanoDownloaded(o.pano, 512) ){
  135. //console.log('512的还没下载好呢!')
  136. e.push(o)
  137. break;//一般512的都是连续下载的,所以后面就都不是512了直接中断
  138. }
  139. this.startDownload(o)
  140. n++
  141. }
  142. }
  143. }
  144. }
  145. testDownload(panoSize, tileSize, callback) {
  146. var n = this.downloadTestResults[panoSize];
  147. if (n)
  148. return void(n === this.freeze.Success ? callback(!0) : n === this.freeze.Fail && callback(!1));
  149. this.downloadTestResults[panoSize] = this.freeze.Testing;
  150. var r = this.panos[0],
  151. o = this.getTileUrl({pano:r, panoSize, tileSize, tileIndex:0} /* r.id, panoSize, tileSize, 0 */),
  152. a = function(t) {
  153. this.downloadTestResults[panoSize] = this.freeze.Success,
  154. callback(!0)
  155. }
  156. .bind(this),
  157. s = function() {
  158. this.downloadTestResults[panoSize] = this.freeze.Fail,
  159. callback(!1)
  160. }
  161. .bind(this);
  162. this.loadImage(o, 0, a, s)
  163. }
  164. startDownload(e) {//开始下载啦
  165. //console.log('startDownload')
  166. startdownloads.push(e)
  167. e.status = DownloadStatus.Downloading;
  168. var t = this.getTileUrl(e/* e.pano.id, e.panoSize, e.tileSize, e.tileIndex, e.pano.alignmentType */);//xzw add alignmentType
  169. if(!t)return;
  170. this.activeDownloads.push(e);
  171. this.loadImage(t, TileDownloader.DOWNLOAD_RETRIES, this.downloadComplete.bind(this, e), this.downloadFailed.bind(this, e))
  172. }
  173. downloadFailed(e, t) {}
  174. downloadComplete(e, t) {//下载成功时
  175. //if (e.panoGroupId === this.panoGroupId) {
  176. var i = this.getPanoLoadCallbacks(e.pano, e.panoSize);
  177. e.status = DownloadStatus.Downloaded,
  178. i && i.onProgress && i.onProgress(e.pano, e.panoSize);
  179. var n = {
  180. panoId: e.pano.id,
  181. image: t,
  182. tileSize: e.tileSize,
  183. panoSize: e.panoSize,
  184. tileIndex: e.tileIndex,
  185. faceTileIndex: e.faceTileIndex,
  186. totalTiles: e.totalTiles,
  187. face: e.face,
  188. tileX: e.tileX,
  189. tileY: e.tileY,
  190. direction: e.direction
  191. };
  192. downloaded[e.pano.id] || (downloaded[e.pano.id]={512:[],1024:[],2048:[]})
  193. downloaded[e.pano.id][e.panoSize] || (downloaded[e.pano.id][e.panoSize] = [])
  194. downloaded[e.pano.id][e.panoSize].push(e)
  195. if(e.panoSize != 512 && downloaded[e.pano.id][512].length<6){
  196. console.warn('没下完')
  197. }
  198. e.image = t,
  199. this.dispatchEvent({type:TileDownloaderEvents.TileDownloadSuccess, desc:n} )
  200. this.isPanoDownloaded(e.pano, e.panoSize) && (n = {
  201. panoId: e.pano.id,
  202. tileSize: e.tileSize,
  203. panoSize: e.panoSize
  204. },
  205. this.dispatchEvent({type:TileDownloaderEvents.PanoDownloadComplete, desc:n}),
  206. i && i.onLoad && i.onLoad(e.pano, e.panoSize))
  207. //}
  208. }
  209. isPanoDownloaded(e, t) {
  210. var i = this.getTileDownloadDescriptors(e, t);
  211. if (i.length <= 0)
  212. return !1;
  213. for (var n = 0; n < i.length; n++) {
  214. var r = i[n];
  215. if (r.status !== DownloadStatus.Downloaded)
  216. return !1
  217. }
  218. return !0
  219. }
  220. setPanoLoadCallbacks(e, t, i, n, r) {
  221. var o = e.id + ":" + this.qualityManager.getPanoSize(t);
  222. this.panoLoadCallbacks[o] = {
  223. onLoad: i,
  224. onFail: n,
  225. onProgress: r
  226. }
  227. }
  228. getPanoLoadCallbacks(e, t) {
  229. var i = e.id + ":" + t;
  230. return this.panoLoadCallbacks[i]
  231. }
  232. buildDownloadDescriptorArray(e) {
  233. for (var t = TileUtils.getTileCountForSize(e), i = [], n = 0; n < t; n++) {
  234. var r = this.buildDownloadDescriptor();
  235. i.push(r)
  236. }
  237. return i
  238. }
  239. buildDownloadDescriptor() {//Descriptor!
  240. var e = {
  241. panoGroupId: null,
  242. pano: null,
  243. panoSize: -1,
  244. tileSize: -1,
  245. tileIndex: -1,
  246. totalTiles: -1,
  247. faceTileIndex: -1,
  248. status: DownloadStatus.None,
  249. url: null,
  250. image: null,
  251. direction: new THREE.Vector3, //该tile在cube中的方向
  252. face: -1,
  253. cubeFace: -1,
  254. tileX: -1,
  255. tileY: -1
  256. };
  257. return e
  258. }
  259. initTileDownloadDescriptors(e, t, i) {
  260. for (var n = 0; n < e.length; n++) {
  261. var r = e[n];
  262. this.initTileDownloadDescriptor(r, t, i, n)
  263. }
  264. }
  265. initTileDownloadDescriptor(desc, pano, size, index) {
  266. var r = size >= TileUtils.TILE_SIZE ? TileUtils.TILE_SIZE : size;
  267. desc.face = TileUtils.getFaceForTile(size, index);//根据顺序得到的face的index
  268. desc.cubeFace = TileUtils.mapFaceToCubemapFace(desc.face);//为了贴图而转化的face index
  269. //desc.panoGroupId = this.panoGroupId;//就是场景号
  270. desc.pano = pano;
  271. desc.panoSize = size;
  272. desc.tileSize = r; //瓦片图size 512
  273. desc.tileIndex = index;
  274. desc.totalTiles = TileUtils.getTileCountForSize(size);
  275. desc.status = DownloadStatus.None;
  276. desc.image = null;
  277. TileUtils.getTileLocation(desc.panoSize, desc.tileIndex, desc);//得到该tile在这个face中的具体位置(tileX等)
  278. TileUtils.getTileVector(desc.panoSize, desc.tileSize, desc.cubeFace, desc.tileX, desc.tileY, TileUtils.LocationOnTile.Center, 0, desc.direction);
  279. }
  280. getTiles(d, sceneNum){
  281. return `https://4dkk.4dage.com/images/images${sceneNum}/${d}`
  282. }
  283. loadImage(e, t, i, n) {
  284. //自己修改了ajax,把getImage改成了loadImg
  285. http.loadImage(e, t).then(function(e) {
  286. i(e)
  287. }).fail(n)
  288. }
  289. }
  290. TileDownloader.prototype.forceQueueTilesForPano = function() {//根据条件开始加载tile
  291. var e = [],
  292. t = [];
  293. return function(pano, size, dir, hFov, vFov, download) {
  294. e.length = 0;
  295. for (var u = this.getTileDownloadDescriptors(pano, size), d = 0; d < u.length; d++) {
  296. var p = u[d];
  297. p.status !== DownloadStatus.None && p.status !== DownloadStatus.Queued || e.push(p)
  298. }
  299. if (dir && e.length > 0) {
  300. TilePrioritizer.sortPanoTiles(e, pano, dir) //按最佳方向排序e
  301. t.length = 0
  302. TileUtils.matchingTilesInDirection(pano, size, dir, hFov, vFov, t);//得到在符合视野标准的集合t
  303. for (var f = 0, g = function(e) {
  304. return e.face === m.face && e.faceTileIndex === m.faceTileIndex
  305. }; f < e.length;) { //过滤掉不符合角度要求的
  306. var m = e[f],
  307. v = t.findIndex(g);
  308. v < 0 ? e.splice(f, 1) : f++
  309. }
  310. }
  311. for (var A = 0; A < e.length; A++){
  312. this.forceQueue.push(e[A]); //装载
  313. }
  314. /* if(e.length){
  315. console.log(e)
  316. } */
  317. this.setStatusForAllDescriptors(this.forceQueue, DownloadStatus.ForceQueued);
  318. this.clearFromQueue(this.priorityQueue, DownloadStatus.ForceQueued, !1);
  319. download && this.processQueueForDownloading(this.forceQueue, !0);
  320. }
  321. }()
  322. TileDownloader.prototype.cleanupActiveDownloads = function() {
  323. var e = [];
  324. return function() {
  325. e.length = 0;
  326. for (var t = 0; t < this.activeDownloads.length; t++) {
  327. var i = this.activeDownloads[t];
  328. i.status !== DownloadStatus.Downloaded && i.status !== DownloadStatus.Failed && e.push(i)
  329. }
  330. this.activeDownloads.length = 0,
  331. this.activeDownloads.push.apply(this.activeDownloads, e)
  332. }
  333. }()
  334. TileDownloader.prototype.getTileUrl = function() {
  335. var e = {
  336. 256: "256",
  337. 512: "512",
  338. 1024: "1k",
  339. 2048: "2k",
  340. 4096: "4k"
  341. },
  342. t = {
  343. face: -1,
  344. faceTileIndex: -1,
  345. tileX: -1,
  346. tileY: -1
  347. };
  348. return function(o={} ) {
  349. var id = o.pano.originID, ////////
  350. panoSize = o.panoSize,
  351. tileSize = o.tileSize,
  352. tileIndex = o.tileIndex,
  353. datasetName = o.pano.pointcloud.name
  354. var metadata = {sceneScheme:10}
  355. TileUtils.getTileLocation(panoSize, tileIndex, t);
  356. var s = Math.floor(panoSize / tileSize),
  357. l = s * s,
  358. h = Math.floor(tileIndex / l),
  359. u = "",
  360. d = '', g = '';
  361. 1 === config.tiling.customCompression && (u = "_" + config.tiling["q" + e[panoSize]]);
  362. /* if (metadata.sceneScheme == 10) */{//阿里云oss的规则
  363. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=';
  364. if (e[panoSize] == '512') {
  365. d += 'image/resize,h_512';
  366. } else {
  367. //4k的图,移动端是1k,pc端是2k,放大才是4k
  368. if (e[panoSize] == '1k' || e[panoSize] == '2k') { //https://4dkk.4dage.com/images/imagesx4iqYDG3/tiles/4k/122_skybox0.jpg?x-oss-process=image/resize,m_lfit,w_1024/crop,w_512,h_512,x_511,y_0
  369. d += 'image/resize,m_lfit,w_' + panoSize + '/crop,w_512,h_512,';
  370. } else {
  371. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=image/crop,w_512,h_512,';
  372. }
  373. //起始位置
  374. if (t.tileX == 0) {
  375. d += 'x_0,';
  376. } else {
  377. d += 'x_' + (512 * t.tileX - 1) + ',';
  378. }
  379. if (t.tileY == 0) {
  380. d += 'y_0';
  381. } else {
  382. d += 'y_' + (512 * t.tileY - 1);
  383. }
  384. /*
  385. if (t.tileX == 0) {
  386. d += 'x_1,';
  387. } else {
  388. d += 'x_' + (512 * t.tileX) + ',';
  389. }
  390. if (t.tileY == 0) {
  391. d += 'y_1';
  392. } else {
  393. d += 'y_' + (512 * t.tileY);
  394. } */
  395. }
  396. d = this.getTiles(d, datasetName);
  397. g = "&"
  398. }
  399. d += g + 'time='+o.pano.pointcloud.timeStamp //加后缀
  400. return d;
  401. }
  402. }();
  403. TileDownloader.tilegen = true;
  404. TileDownloader.IDLE_REFRESH_DELAY = 500;
  405. TileDownloader.ACTIVE_REFRESH_DELAY = 16;
  406. TileDownloader.DOWNLOAD_RETRIES = 4;
  407. // var tileconc = TileDownloader.tilegen ? 6 : 2;
  408. // publicObjectSet.tileDownloader = new TileDownloader({
  409. // concurrentDownloads: tileconc
  410. // });
  411. // export default new TileDownloader({
  412. // concurrentDownloads: TileDownloader.tilegen ? 6 : 2
  413. // })
  414. /* export default new TileDownloader({
  415. concurrentDownloads: TileDownloader.tilegen ? 6 : 2
  416. }) */
  417. export default TileDownloader