thematic-earth
Version:
HTML-based, whole-Earth thematic maps using locally hosted data layers
2 lines • 4.84 kB
JavaScript
/* Copyright (c) 2023 Read Write Tools. Legal use subject to the Thematic Earth Software License Agreement. */
import CollisionMatrix from'../labels/collision-matrix.class.js';import ProxyPoint from'../labels/proxy-point.class.js';import ProxyLine from'../labels/proxy-line.class.js';import ProxyPolygon from'../labels/proxy-polygon.class.js';import FT from'../enum/feature-type.enum.js';import LS from'../enum/labeling-state.enum.js';import LP from'../enum/labeling-phase.enum.js';import expect from'../dev/expect.js';import aver from'../dev/aver.js';import terminal from'../dev/terminal.js';export default class LabelEngine{constructor(e,t,i){this.thematicEarthElement=e,this.canvas=e.canvas,this.catalog=i,this.queue=[],this.state=LS.COMPLETE,this.collisionMatrix=null,this.phaseCompletionCounter=new Array(LP.NUM_PHASES).fill(-1),this.idleCallbackId=0,this.haltTime=0,this.registerListeners(),Object.seal(this)}registerListeners(){this.thematicEarthElement.signal.listen('catalog/beginRender',(()=>{this.state=LS.QUEUEING,this.flushQueue()})),this.thematicEarthElement.signal.listen('catalog/endRender',(()=>{this.state=LS.PENDING,this.idleCallbackId=requestIdleCallback(this.computeLayout.bind(this))}))}flushQueue(){this.queue=[];for(let e=0;e<LP.NUM_PHASES;e++)this.phaseCompletionCounter[e]=-1;this.collisionMatrix=null}addToQueue(e,t,i,a){switch(aver(this.state==LS.QUEUEING),a){case FT.POINT:this.queue.push(new ProxyPoint(e,t,i));break;case FT.LINE:this.queue.push(new ProxyLine(e,t,i));break;case FT.POLYGON:this.queue.push(new ProxyPolygon(e,t,i));break;default:terminal.logic(`Unexpected featureType ${a}`)}}computeLayout(e){if(expect(e,['IdleDeadline','Object']),this.state!=LS.QUEUEING&&this.state!=LS.COMPLETE){this.state==LS.PENDING&&(this.state=LS.WORKING);var t=e.timeRemaining();if(0!=t){this.haltTime=performance.now()+t;for(let e=0;e<LP.NUM_PHASES;e++)this.phaseCompletionCounter[e]<this.queue.length-1&&this.timeAvailable()&&monitorPerformance(e,(()=>{this.executePhase(e)}));this.state==LS.WORKING&&(this.idleCallbackId=requestIdleCallback(this.computeLayout.bind(this)))}else this.idleCallbackId=requestIdleCallback(this.computeLayout.bind(this))}}timeAvailable(){return performance.now()<this.haltTime}executePhase(e){expect(e,'Number');var t=this.phaseCompletionCounter[e];switch(e){case LP.INIT_COLLISION_MATRIX:null==this.collisionMatrix&&this.timeAvailable()&&(this.collisionMatrix=new CollisionMatrix(this.catalog,this.canvas,this.canvas.width,this.canvas.height));break;case LP.GET_FEATURE_DATA:t=this.iterateOverQueue(t,(e=>{e.getFeatureData(this.catalog,this.canvas)}));break;case LP.COMPUTE_TEXT_METRICS:t=this.iterateOverQueue(t,(e=>{e.computeTextMetrics(this.catalog,this.canvas)}));break;case LP.DISQUALIFICATION_CRITERIA:t=this.iterateOverQueue(t,(e=>{e.disqualificationCriteria()}));break;case LP.POSSIBLE_PLACEMENTS:t=this.iterateOverQueue(t,(e=>{e.possiblePlacements(this.canvas)}));break;case LP.RESERVE_SYMBOLS:t=this.iterateOverQueue(t,(e=>{e.reserveSymbols(this.collisionMatrix)}));break;case LP.COLLISION_ADJUSTMENT:t=this.iterateOverQueue(t,(e=>{e.collisionAdjustment(this.canvas,this.collisionMatrix)}));break;case LP.DRAW_RESERVED_PIXELS:-1==t&&(t=this.queue.length);break;case LP.BOUNDING_BOX:t=this.iterateOverQueue(t,(e=>{e.drawBoundingBox(this.canvas)}));break;case LP.DRAW_LABELS:(t=this.iterateOverQueue(t,(e=>{e.drawLabel(this.canvas)})))==this.queue.length-1&&(this.state=LS.COMPLETE);break;default:terminal.logic(`Unhandled phase in label engine ${e}`)}this.phaseCompletionCounter[e]=t}iterateOverQueue(e,t){if(expect(e,'Number'),expect(t,'Function'),0==this.queue.length)return-1;for(var i=e+1;i<this.queue.length;i++){if(0==this.timeAvailable())return i-1;var a=this.queue[i];0==a.isDisqualified&&t(a)}return i-1}}function phaseNameFromValue(e){switch(e){case 0:return'INIT_COLLISION_MATRIX';case 1:return'GET_FEATURE_DATA';case 2:return'COMPUTE_TEXT_METRICS';case 3:return'DISQUALIFICATION_CRITERIA';case 4:return'POSSIBLE_PLACEMENTS';case 5:return'RESERVE_SYMBOLS';case 6:return'COLLISION_ADJUSTMENT';case 7:return'DRAW_RESERVED_PIXELS';case 8:return'BOUNDING_BOX';case 9:return'DRAW_LABELS'}return'invalid'}function monitorPerformance(e,t){var i=performance.now();t();performance.now()}window.requestIdleCallback||(window.requestIdleCallback=function(e,t){var i=(t=t||{}).timeout||1,a=performance.now();return setTimeout((function(){e({get didTimeout(){return!t.timeout&&performance.now()-a-1>i},timeRemaining:function(){return Math.max(0,performance.now()-a+1)}})}),1)}),window.cancelIdleCallback||(window.cancelIdleCallback=function(e){clearTimeout(e)}),window.requestAnimationFrame||(window.requestAnimationFrame=function(e){return window.setTimeout((function(){e(Date.now())}),1e3/60)}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(e){clearTimeout(e)});