UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

210 lines (197 loc) 6.13 kB
/** * Create points from a an array of json dictionaries * * @remarks * This node is similar to the [Data SOP], but will fetch the data from a url. * */ import {TypedSopNode} from './_Base'; import {JsonDataLoader} from '../../../core/loader/geometry/JSONDataLoader'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {BaseParamType} from '../../params/_Base'; import {BaseNodeType} from '../_Base'; import {CsvLoader} from '../../../core/loader/geometry/Csv'; import {BufferGeometry} from 'three'; import {ObjectType} from '../../../core/geometry/Constant'; import {ASSETS_ROOT} from '../../../core/loader/AssetsUtils'; import {isBooleanTrue} from '../../../core/BooleanValue'; import {Poly} from '../../Poly'; import {ParamEvent} from '../../poly/ParamEvent'; import {SopType} from '../../poly/registers/nodes/types/Sop'; import {EXTENSIONS_BY_NODE_TYPE_BY_CONTEXT} from '../../../core/loader/FileExtensionRegister'; import {NodeContext} from '../../poly/NodeContext'; export enum DataType { JSON = 'json', CSV = 'csv', } export const DATA_TYPES: DataType[] = [DataType.JSON, DataType.CSV]; const DEFAULT_URL = `${ASSETS_ROOT}/nodes/sop/DataUrl/basic.json`; class DataUrlSopParamsConfig extends NodeParamsConfig { /** @param sets if the data is interpreted as json or csv */ dataType = ParamConfig.INTEGER(DATA_TYPES.indexOf(DataType.JSON), { menu: { entries: DATA_TYPES.map((t, i) => { return { name: t, value: i, }; }), }, }); /** @param the url to fetch the data from */ url = ParamConfig.STRING(DEFAULT_URL, { fileBrowse: {extensions: EXTENSIONS_BY_NODE_TYPE_BY_CONTEXT[NodeContext.SOP][SopType.DATA_URL]}, }); // // JSON params // /** @param if the data is inside the payload, defines the prefix to read it from here */ jsonDataKeysPrefix = ParamConfig.STRING('', { visibleIf: {dataType: DATA_TYPES.indexOf(DataType.JSON)}, }); /** @param which entries are skipped */ skipEntries = ParamConfig.STRING('', { visibleIf: {dataType: DATA_TYPES.indexOf(DataType.JSON)}, }); /** @param sets if some attributes should be converted */ convert = ParamConfig.BOOLEAN(0, { visibleIf: {dataType: DATA_TYPES.indexOf(DataType.JSON)}, }); /** @param sets which attributes should be converted from string to numeric */ convertToNumeric = ParamConfig.STRING('', { visibleIf: { dataType: DATA_TYPES.indexOf(DataType.JSON), convert: 1, }, }); // // CSV params // /** @param when fetching from a csv, the attribute names will not be present. Those can then be mentioned here */ readAttribNamesFromFile = ParamConfig.BOOLEAN(1, { visibleIf: {dataType: DATA_TYPES.indexOf(DataType.CSV)}, }); /** @param list of attributes names when fetching from a csv */ attribNames = ParamConfig.STRING('height scale', { visibleIf: { dataType: DATA_TYPES.indexOf(DataType.CSV), readAttribNamesFromFile: 0, }, }); // // reload // /** @param reload the url */ reload = ParamConfig.BUTTON(null, { callback: (node: BaseNodeType, param: BaseParamType) => { DataUrlSopNode.PARAM_CALLBACK_reload(node as DataUrlSopNode, param); }, }); } const ParamsConfig = new DataUrlSopParamsConfig(); export class DataUrlSopNode extends TypedSopNode<DataUrlSopParamsConfig> { override paramsConfig = ParamsConfig; static override type() { return SopType.DATA_URL; } override async cook() { this._load(); } private _load() { switch (DATA_TYPES[this.pv.dataType]) { case DataType.JSON: return this._loadJSON(); case DataType.CSV: return this._loadCSV(); } } // private _clearLoadedBlob() { // switch (DATA_TYPES[this.pv.dataType]) { // case DataType.JSON: // return this._resetJSON(); // case DataType.CSV: // return this._resetCSV(); // } // } override dispose(): void { super.dispose(); Poly.blobs.clearBlobsForNode(this); } private _url() { // do not use assetsRoot here, as it would use it twice // as it is already used in the loader. // const assets_root = this.scene().assets.root(); // if (assets_root) { // return `${assets_root}${this.pv.url}`; // } else { return this.pv.url; // } } // // // JSON // // private _loadJSON() { const loader = new JsonDataLoader( this._url(), { dataKeysPrefix: this.pv.jsonDataKeysPrefix, skipEntries: this.pv.skipEntries, doConvert: isBooleanTrue(this.pv.convert), convertToNumeric: this.pv.convertToNumeric, }, this ); loader.load(this._onLoad.bind(this), undefined, this._onError.bind(this)); } // private _resetJSON() { // const loader = new JsonDataLoader(this._url(), this.scene()); // loader.deregisterUrl(); // } private _onLoad(geometry: BufferGeometry) { this.setGeometry(geometry, ObjectType.POINTS); } private _onError(error: ErrorEvent) { this.states.error.set(`could not load geometry from ${this._url()} (${error})`); this.cookController.endCook(); } // // // CSV // // private async _loadCSV() { const attribNames = isBooleanTrue(this.pv.readAttribNamesFromFile) ? undefined : this.pv.attribNames.split(' '); const loader = new CsvLoader(this._url(), attribNames, this); const geometry = await loader.load(); if (geometry) { this.setGeometry(geometry, ObjectType.POINTS); } else { this.states.error.set('could not generate points'); } } // private _resetCSV() { // const attribNames: string[] = []; // const loader = new CsvLoader(this._url(), this.scene(), attribNames, this); // loader.deregisterUrl(); // } // async _on_open_url(){ // const url = await this.param('url').eval_p() // const a = document.createElement('a') // a.href = url // a.setAttribute('target', '_blank') // a.click() // } static PARAM_CALLBACK_reload(node: DataUrlSopNode, param: BaseParamType) { node.param_callback_reload(); } param_callback_reload() { // this._clearLoadedBlob(); // this._previous_param_url = null // set the param dirty is preferable, in case this is used to refresh a local asset this.p.url.setDirty(); this.p.url.emit(ParamEvent.ASSET_RELOAD_REQUEST); // this.setDirty() } }