UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

6 lines (5 loc) 7.51 kB
/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.32/esri/copyright.txt for details. */ import has from"../../../../core/has.js";import e from"../../../../core/Logger.js";import{create as t}from"../../../../core/libs/gl-matrix-2/factories/mat2df32.js";import{AFeatureTile as s}from"./AFeatureTile.js";import{RESHUFFLING_EXEMPT_MEMORY_BYTES as i,RESHUFFLING_TARGET_MEMORY_EFFICIENCY as r,RESHUFFLING_EXEMPT_DRAW_CALLS as o,RESHUFFLING_TARGET_DRAW_EFFICIENCY as d,tileSize as n}from"./definitions.js";import h from"./DisplayEntity.js";import{FeatureBatchingStrategy as a}from"./enums.js";import{DisplayList as l}from"./FeatureDisplayList.js";import{ReshufflePlan as f}from"./ReshufflePlan.js";import{LabelMetric as u}from"./collisions/LabelMetric.js";import{MappedMesh as p}from"./cpuMapped/MappedMesh.js";import{debugMeshDataInfo as _}from"./mesh/meshDebugUtils.js";import m from"./util/Reader.js";import{deserializeList as c}from"./util/serializationUtils.js";const y=()=>e.getLogger("esri.views.2d.engine.webgl.FeatureTile");let g=0;class b extends s{constructor(e,s,i,r,o=!1){super(e,s,i,r),this._meshes=new Map,this._entities=[],this._invalidated=!1,this._nextUploadAllowed=!1,this.tileAge=g++,this._metrics=[],this._entityIds=new Set,this._entityIdsFromBuffer=new Set,this._attributeEpoch=0,this._encounteredEnd=!1,this._objectIdMap=null,this.visible=!0,this.transforms.labelMat2d=t(),this.enableDeferredUploads=o}destroy(){super.destroy(),this.clear()}clear(){for(const e of this._meshes.values())e.destroy();this._meshes.clear(),this._entities=[],this._metrics=[],this._displayList=null,this._invalidated=!0,this._entityIds.clear(),this._nextUploadAllowed=!0}beforeRender(e){super.beforeRender(e),this._needsReshuffle&&e.reshuffleManager.schedule(this)}tryReady(e){const t=this._invalidated&&!this._uploadAllowed;return!(this.isReady||t||!this._encounteredEnd||!(e>=this._attributeEpoch))&&(has("esri-2d-update-debug")&&console.debug(`Tile[${this.key.id}] FeatureTile.ready [epoch=${e}]`),this.ready(),this.requestRender(),!0)}get labelMetrics(){return this._metrics}get hasData(){return!!this._meshes.size}get hasAnimations(){return!!this._objectIdMap}get needsUpload(){return this._invalidated}get _uploadAllowed(){return!this.enableDeferredUploads||this._nextUploadAllowed}upload(){this._nextUploadAllowed=!0}getDisplayList(e,t){if(this._uploadAllowed&&this._invalidated){this._entities.sort(((e,t)=>{const s=t.sortKey,i=e.sortKey;return i===s?e.id-t.id:i-s})),t===a.BATCHING&&this.reshuffle(!0),this._displayList=l.fromDisplayEntities(this._entities,this,e,t);for(const e of this._meshes.values())e.upload();this.debugInfo.display.length=this._displayList.length,this.debugInfo.display.minOrderedLength=this._displayList.minOrderedLength,this.debugInfo.display.minUnorderedLength=this._displayList.minUnorderedLength,this.requestRender(),this._invalidated=!1,this._nextUploadAllowed=!1}return this._displayList}getMesh(e){if(!this._meshes.has(e))throw new Error(`InternalError: Unable to find VAO for instance: ${e}`);return this._meshes.get(e)}getSortKeys(e){const t=new Map;for(const{id:s,sortKey:i}of this._entities)if(e.has(s)&&t.set(s,i),t.size===e.size)break;return t}onMessage(e){if(e.objectIdMap)for(const t in e.objectIdMap)this._objectIdMap||(this._objectIdMap={}),this._objectIdMap[t]=e.objectIdMap[t];switch(e.type){case"append":this._onAppendMessage(e);break;case"update":this._onUpdateMessage(e)}if(this._aggregateMemoryStats(),this.requestRender(),e.end){if(has("esri-2d-update-debug")&&console.debug(`Tile[${this.key.id}] FeatureTile.end [epoch=${e.attributeEpoch}]`),!e.attributeEpoch)throw new Error("InternalError: Attribute epoch not defined.");this._attributeEpoch=e.attributeEpoch,this._encounteredEnd=!0}}_onAppendMessage(e){if(has("esri-2d-update-debug")&&console.debug(`Tile[${this.key.id}] FeatureTile.append`,{append:_(e?.append)}),e.clear&&this.clear(),!e.append)return;const t=c(new m(e.append.entities),h);this._insert(t,e.append.data,!1)}_onUpdateMessage(e){has("esri-2d-update-debug")&&console.debug(`Tile[${this.key.id}] FeatureTile.update`,{isPixelBuffer:e.isPixelBuffer,modify:_(e.modify),remove:e.remove});const t=c(new m(e.modify.entities),h),s=t.map((e=>e.id)),i=e.isPixelBuffer??!1,r=[...e.remove,...s];i?this._removeByIdsFromBuffer(r):this._removeByIds(r),this._insert(t,e.modify.data,i)}reshuffle(e=!1){if(this.destroyed)return;const t=new Map;for(const s of this._entities)for(const i of s.records){const s=this._meshes.get(i.instanceId);let r=t.get(s);r||(r=new f(e),t.set(s,r)),r.copyRecord(i)}for(const[s,i]of t)s.reshuffle(i);this._invalidated=!0,this._aggregateMemoryStats(),has("esri-2d-update-debug")&&y().info(`Tile ${this.key.id} was reshuffled.`)}copyPixelBufferedEntitesFrom(e,t,s,i){const r=s*n,o=i*n;for(const d of e._entities){let s=null;for(const i of d.records)if(i.overlaps&t){const t=e.getMesh(i.instanceId),n=this._ensureMesh(i.instanceId,t.layout).copyRecordFrom(t,i,r,o);s||(s=new h(d.id,d.sortKey),this._entityIdsFromBuffer.add(d.id),this._entities.push(s)),s.records.push(n)}}this._invalidated=!0}_ensureMesh(e,t){return this._meshes.has(e)||this._meshes.set(e,new p(this._stage.bufferPool,t)),this._meshes.get(e)}_insert(e,t,s){if(!e.length)return;this._removeDuplicatedBufferedEntites(e);const i=this._insertVertexData(t);for(const r of e){for(const e of r.records)e.updateBaseOffsets(i.get(e.instanceId));s?this._tryInsertBufferedEntity(r):this._insertEntity(r)}this._invalidated=!0}_insertVertexData(e){const t=new Map;for(const s of e){const{instanceId:e,layout:i}=s,r=this._ensureMesh(e,i).append(s);if(s.metrics){const e=c(new m(s.metrics),u)??[];this._metrics.push(...e)}t.set(e,r)}return t}_insertEntity(e){has("esri-2d-update-debug")&&this._entityIds.has(e.id)&&console.error(`Tile ${this.key.id} insertEnitty: Already have entityId ${e.id}`),this._entityIds.add(e.id),this._entities.push(e)}_tryInsertBufferedEntity(e){this._entityIds.has(e.id)?this._removeRecordsFromMesh(e.records):(this._entityIdsFromBuffer.add(e.id),this._entities.push(e))}_removeDuplicatedBufferedEntites(e){if(!this._entityIdsFromBuffer.size)return;const t=[];for(const s of e)this._entityIdsFromBuffer.has(s.id)&&t.push(s.id);this._removeByIds(t)}_removeByIdsFromBuffer(e){this._removeByIds(e.filter((e=>this._entityIdsFromBuffer.has(e))))}_removeByIds(e){if(0===e.length)return;const t=new Set(e),s=[];for(const i of this._entities)t.has(i.id)?this._remove(i):s.push(i);this._entities=s,this._invalidated=!0}_remove(e){this._removeRecordsFromMesh(e.records),this._entityIds.delete(e.id),this._entityIdsFromBuffer.delete(e.id);for(let t=this._metrics.length-1;t>=0;t--)this._metrics[t].entityTexel===e.id&&this._metrics.splice(t,1)}_removeRecordsFromMesh(e){for(const t of e){const{instanceId:e,indexStart:s,indexCount:i,vertexStart:r,vertexCount:o}=t;this._meshes.get(e)?.remove(s,i,r,o)}}_aggregateMemoryStats(){this.debugInfo.memory.bytesUsed=0,this.debugInfo.memory.bytesReserved=0;for(const e of this._meshes.values())this.debugInfo.memory.bytesUsed+=e.memoryStats.bytesUsed,this.debugInfo.memory.bytesReserved+=e.memoryStats.bytesReserved}get _needsReshuffle(){if(this.destroyed)return!1;const{bytesUsed:e,bytesReserved:t}=this.debugInfo.memory,s=e/t,{minOrderedLength:n,length:h}=this.debugInfo.display;return t>i&&s<r||h>o&&n/h<d}get entityIds(){return this._objectIdMap?this._entities.map((({id:e})=>({objectId:this._objectIdMap[e],displayId:e}))):[]}}export{b as FeatureTile};