layers_i3s_I3SLayer.js

import { Layer } from "../Layer";
import { I3SPointNode } from './I3SPointNode';


//const TRANSFORM = require('transform-coordinates')
import * as TRANSFORM from '../../transform/Transformer.js';

/**
 * A layer for loading I3S data (only points supported)
 */
class I3SLayer extends Layer {
    /**
     * 
     * @param {Object} properties 
     * @param {String|Number} properties.id layer id should be unique
     * @param {String} properties.name the name can be anything you want and is intended for labeling
     * @param {String} properties.url the service url
     * @param {String} properties.layer the service layer to display
     * @param {Number} [properties.geometricErrorMultiplier = 1] (optional) between 0 and infinity, defaults to 1. controls the level of detail.
     * @param {Number[]} [properties.bounds=[-180, -90, 180, 90]]  min longitude, min latitude, max longitude, max latitude in degrees
     * @param {Boolean} [properties.visible = true] layer will be rendered if true (true by default)
     */
    constructor(properties) {
        super(properties);
        this.isI3SLayer = true;
        const self = this;
        // first fetch the layer information
        fetch(properties.url + "/layers/" + properties.layer + "?f=json").then(result => {
            if (!result.ok) {
                throw new Error(`couldn't load "${properties.url}". Request failed with status ${result.status} : ${result.statusText}`);
            }
            result.json().then(json => {
                self.info = json;
                switch (self.info.layerType) {
                    case "Point":
                        self.root = new I3SPointNode({
                            url: properties.url + "/layers/" + properties.layer + "/nodes/",
                            node: "root",
                            geometricErrorMultiplier: properties.geometricErrorMultiplier,
                            transform: TRANSFORM.transform("EPSG:4326", 'EPSG:4978')
                        });
                        if (self.addToSceneCallback) self.addToSceneCallback();
                        break;
                    default: throw "unsupported layer type : " + self.info.layerType;
                }
            });
        });
    }

    addToScene(scene, camera) {
        const self = this;

        function addToScene () {
            scene.add(self.root);
            self.updateInterval.clearInterval();
            self.updateInterval = setIntervalAsync(function () {
                if (self.root) self.root.update(camera);
            }, 50);
        }
        if (!!self.root) {
            addToScene();
        }else{
            self.addToSceneCallback = addToScene;
        }
        
    }


    dispose() {
        if (this.root.dispose) this.root.dispose();
        clearIntervalAsync(this.updateInterval);
    }
}
export { I3SLayer }

function setIntervalAsync(fn, delay) {
    let timeout;

    const run = async () => {
        const startTime = Date.now();
        try {
            await fn();
        } catch (err) {
            console.error(err);
        } finally {
            const endTime = Date.now();
            const elapsedTime = endTime - startTime;
            const nextDelay = elapsedTime >= delay ? 0 : delay - elapsedTime;
            timeout = setTimeout(run, nextDelay);
        }
    };

    timeout = setTimeout(run, delay);

    return { clearInterval: () => clearTimeout(timeout) };
}