diff --git a/package.json b/package.json index c213472..d4dda85 100644 --- a/package.json +++ b/package.json @@ -39,13 +39,15 @@ "clean:lib": "rimraf lib", "clean:labextension": "rimraf bqplot-gl/labextension", "clean:nbextension": "rimraf bqplot-gl/nbextension/static/index.js", - "lint": "eslint . --ext .ts,.tsx --fix", - "lint:check": "eslint . --ext .ts,.tsx", "prepack": "yarn run build:lib", "watch": "npm-run-all -p watch:*", "watch:lib": "tsc -w", "watch:nbextension": "webpack --watch --mode=development", - "watch:labextension": "jupyter labextension watch ." + "watch:labextension": "jupyter labextension watch .", + "prettier:check": "prettier src --check", + "prettier:fix": "prettier src --write", + "eslint:check": "eslint src --ext .ts", + "eslint:fix": "eslint src --ext .ts --fix" }, "dependencies": { "@jupyter-widgets/base": "^1.1.10 || ^2.0.0 || ^3.0.0 || ^4.0.0", diff --git a/src/LinesGLModel.ts b/src/LinesGLModel.ts index 41fe003..6089eb0 100644 --- a/src/LinesGLModel.ts +++ b/src/LinesGLModel.ts @@ -17,7 +17,6 @@ import { MODULE_NAME, MODULE_VERSION } from './version'; import { LinesModel } from 'bqplot'; - export class LinesGLModel extends LinesModel { defaults() { return { @@ -27,8 +26,8 @@ export class LinesGLModel extends LinesModel { _model_module_version: LinesGLModel.model_module_version, _view_name: LinesGLModel.view_name, _view_module: LinesGLModel.view_module, - _view_module_version: LinesGLModel.view_module_version - } + _view_module_version: LinesGLModel.view_module_version, + }; } static model_name = 'LinesGLModel'; diff --git a/src/LinesGLView.ts b/src/LinesGLView.ts index 25d4a26..1bee55a 100644 --- a/src/LinesGLView.ts +++ b/src/LinesGLView.ts @@ -1,10 +1,6 @@ -import { - isLinearScale -} from 'bqscales'; +import { isLinearScale } from 'bqscales'; -import { - Lines -} from 'bqplot'; +import { Lines } from 'bqplot'; import * as THREE from 'three'; @@ -23,20 +19,18 @@ import { LinesGLModel } from './LinesGLModel'; import { Values } from './values'; - export class LinesGLView extends Lines { - async render() { await super.render(); // Create material for markers this.material = new THREE.LineMaterial(); - this.material.uniforms.domain_x = { type: "2f", value: [0., 1.] }; - this.material.uniforms.domain_y = { type: "2f", value: [0., 1.] }; - this.material.uniforms.range_x = { type: "2f", value: [0., 1.] }; - this.material.uniforms.range_y = { type: "2f", value: [0., 1.] }; - this.material.uniforms.diffuse = {type: '3f', value: [1, 0, 0]}; - this.material.uniforms.opacity = {type: 'f', value: 1.0}; + this.material.uniforms.domain_x = { type: '2f', value: [0, 1] }; + this.material.uniforms.domain_y = { type: '2f', value: [0, 1] }; + this.material.uniforms.range_x = { type: '2f', value: [0, 1] }; + this.material.uniforms.range_y = { type: '2f', value: [0, 1] }; + this.material.uniforms.diffuse = { type: '3f', value: [1, 0, 0] }; + this.material.uniforms.opacity = { type: 'f', value: 1.0 }; this.material.defines.USE_SCALE_X = true; this.material.defines.USE_SCALE_Y = true; @@ -68,8 +62,11 @@ export class LinesGLView extends Lines { }); } - beforeCompile(shader) {// we include the scales header, and a snippet that uses the scales - shader.vertexShader = "// added by bqplot-image-gl\n#include \n // added by bqplot-image-gl\n" + shader.vertexShader; + beforeCompile(shader) { + // we include the scales header, and a snippet that uses the scales + shader.vertexShader = + '// added by bqplot-image-gl\n#include \n // added by bqplot-image-gl\n' + + shader.vertexShader; const transform = ` vec3 instanceStart_transformed = instanceStart; @@ -83,36 +80,48 @@ export class LinesGLView extends Lines { `; // we modify the shader to replace a piece - const begin = 'vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );' + const begin = 'vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );'; const offset_begin = shader.vertexShader.indexOf(begin); if (offset_begin == -1) { - console.error('Could not find magic begin line in shader'); + console.error('Could not find magic begin line in shader'); } const end = 'vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );'; const offset_end = shader.vertexShader.indexOf(end); if (offset_end == -1) { - console.error('Could not find magic end line in shader'); + console.error('Could not find magic end line in shader'); } - shader.vertexShader = shader.vertexShader.slice(0, offset_begin) + transform + shader.vertexShader.slice(offset_end + end.length); + shader.vertexShader = + shader.vertexShader.slice(0, offset_begin) + + transform + + shader.vertexShader.slice(offset_end + end.length); } updateGeometry() { - const scalar_names = ["x", "y", "z"]; + const scalar_names = ['x', 'y', 'z']; const vector4_names = []; const get_value = (name, index, default_value) => { - if (name === "z") { - return 0; - } - return this.model.get(name); - } + if (name === 'z') { + return 0; + } + return this.model.get(name); + }; const sequence_index = 0; // not used (see ipyvolume) - const current = new Values(scalar_names, [], get_value, sequence_index, vector4_names); - current.ensure_array('z') - current.merge_to_vec3(["x", "y", "z"], "position"); + const current = new Values( + scalar_names, + [], + get_value, + sequence_index, + vector4_names + ); + current.ensure_array('z'); + current.merge_to_vec3(['x', 'y', 'z'], 'position'); // important to reset this, otherwise we may use an old buffered value // Note that if we upgrade threejs, this may be named differently https://github.com/mrdoob/three.js/issues/18990 this.geometry.maxInstancedCount = undefined; - this.geometry.setDrawRange(0, Math.min(this.model.get('x').length, this.model.get('y').length)); + this.geometry.setDrawRange( + 0, + Math.min(this.model.get('x').length, this.model.get('y').length) + ); this.geometry.setPositions(current.array_vec3['position']); this.updateScene(); @@ -126,10 +135,10 @@ export class LinesGLView extends Lines { const color = new THREE.Color(this.model.get('colors')[0]); this.material.color = color.toArray(); const opacities = this.model.get('opacities'); - if(opacities && opacities.length) { - this.material.uniforms.opacity.value = opacities[0]; + if (opacities && opacities.length) { + this.material.uniforms.opacity.value = opacities[0]; } else { - this.material.uniforms.opacity.value = 1.; + this.material.uniforms.opacity.value = 1; } this.updateScene(); } @@ -143,8 +152,12 @@ export class LinesGLView extends Lines { const x_scale = this.scales.x ? this.scales.x : this.parent.scale_x; const y_scale = this.scales.y ? this.scales.y : this.parent.scale_y; - this.material.defines.SCALE_TYPE_X = isLinearScale(x_scale) ? ScaleType.SCALE_TYPE_LINEAR : ScaleType.SCALE_TYPE_LOG; - this.material.defines.SCALE_TYPE_Y = isLinearScale(y_scale) ? ScaleType.SCALE_TYPE_LINEAR : ScaleType.SCALE_TYPE_LOG; + this.material.defines.SCALE_TYPE_X = isLinearScale(x_scale) + ? ScaleType.SCALE_TYPE_LINEAR + : ScaleType.SCALE_TYPE_LOG; + this.material.defines.SCALE_TYPE_Y = isLinearScale(y_scale) + ? ScaleType.SCALE_TYPE_LINEAR + : ScaleType.SCALE_TYPE_LOG; this.material.needsUpdate = true; } @@ -163,7 +176,10 @@ export class LinesGLView extends Lines { this.material.uniforms['range_x'].value = range_x; this.material.uniforms['range_y'].value = [range_y[1], range_y[0]]; - this.material.uniforms['resolution'].value = [fig.plotarea_width, fig.plotarea_height]; + this.material.uniforms['resolution'].value = [ + fig.plotarea_width, + fig.plotarea_height, + ]; this.updateMaterialScales(); fig.renderer.render(this.scene, fig.camera); diff --git a/src/ScatterGLModel.ts b/src/ScatterGLModel.ts index 572abf6..726fd2c 100644 --- a/src/ScatterGLModel.ts +++ b/src/ScatterGLModel.ts @@ -17,7 +17,6 @@ import { ScatterModel } from 'bqplot'; import { MODULE_NAME, MODULE_VERSION } from './version'; - export class ScatterGLModel extends ScatterModel { defaults() { return { @@ -27,7 +26,7 @@ export class ScatterGLModel extends ScatterModel { _model_module_version: ScatterGLModel.model_module_version, _view_name: ScatterGLModel.view_name, _view_module: ScatterGLModel.view_module, - _view_module_version: ScatterGLModel.view_module_version + _view_module_version: ScatterGLModel.view_module_version, }; } diff --git a/src/ScatterGLView.ts b/src/ScatterGLView.ts index c181c6d..ab2043f 100644 --- a/src/ScatterGLView.ts +++ b/src/ScatterGLView.ts @@ -13,12 +13,7 @@ * limitations under the License. */ -import { - Mark, - symbol as bqSymbol, - deepCopy, - Scale -} from 'bqplot'; +import { Mark, symbol as bqSymbol, deepCopy, Scale } from 'bqplot'; import * as d3 from 'd3'; import * as _ from 'underscore'; import { ScatterGLModel } from './ScatterGLModel'; @@ -278,8 +273,7 @@ export class ScatterGLView extends Mark { const color_parameters = this.getColorAttributeParameters(); this.color = this.initializeAttribute('color', color_parameters); - this.material.defines['USE_COLORMAP'] = - color_parameters.use_colormap; + this.material.defines['USE_COLORMAP'] = color_parameters.use_colormap; this.material.defines['USE_SCALE_X'] = true; this.material.defines['USE_SCALE_Y'] = true; @@ -511,36 +505,26 @@ export class ScatterGLView extends Mark { _.each(['selected', 'hovered'], (style_type) => { _.each(['stroke', 'fill', 'opacity'], (style_property) => { - this.material.uniforms[ - `has_${style_type}_${style_property}` - ].value = Boolean( - this.model.get(`${style_type}_style`)[style_property] - ); - this.material.uniforms[ - `has_un${style_type}_${style_property}` - ].value = Boolean( - this.model.get(`un${style_type}_style`)[style_property] - ); + this.material.uniforms[`has_${style_type}_${style_property}`].value = + Boolean(this.model.get(`${style_type}_style`)[style_property]); + this.material.uniforms[`has_un${style_type}_${style_property}`].value = + Boolean(this.model.get(`un${style_type}_style`)[style_property]); if (_.contains(['opacity'], style_property)) { - this.material.uniforms[ - `${style_type}_${style_property}` - ].value = this.model.get(`${style_type}_style`)[style_property]; - this.material.uniforms[ - `un${style_type}_${style_property}` - ].value = this.model.get(`un${style_type}_style`)[style_property]; + this.material.uniforms[`${style_type}_${style_property}`].value = + this.model.get(`${style_type}_style`)[style_property]; + this.material.uniforms[`un${style_type}_${style_property}`].value = + this.model.get(`un${style_type}_style`)[style_property]; } else { - this.material.uniforms[ - `${style_type}_${style_property}` - ].value = color_to_array_rgba( - this.model.get(`${style_type}_style`)[style_property], - 'green' - ); - this.material.uniforms[ - `un${style_type}_${style_property}` - ].value = color_to_array_rgba( - this.model.get(`un${style_type}_style`)[style_property], - 'green' - ); + this.material.uniforms[`${style_type}_${style_property}`].value = + color_to_array_rgba( + this.model.get(`${style_type}_style`)[style_property], + 'green' + ); + this.material.uniforms[`un${style_type}_${style_property}`].value = + color_to_array_rgba( + this.model.get(`un${style_type}_style`)[style_property], + 'green' + ); } }); }); @@ -811,8 +795,7 @@ export class ScatterGLView extends Mark { const color_parameters = this.getColorAttributeParameters(); this.color = this.updateAttribute('color', this.color, color_parameters); this.color.normalized = color_parameters.normalized; - this.material.defines['USE_COLORMAP'] = - color_parameters.use_colormap; + this.material.defines['USE_COLORMAP'] = color_parameters.use_colormap; this.material.needsUpdate = true; @@ -891,8 +874,7 @@ export class ScatterGLView extends Mark { if (marker === 'circle') { // same as in ./Markers.js - this.material.uniforms.marker_scale.value = - 1 / Math.sqrt(Math.PI); + this.material.uniforms.marker_scale.value = 1 / Math.sqrt(Math.PI); this.material.defines['FAST_DRAW'] = FAST_CIRCLE; } if (marker === 'square') { @@ -904,8 +886,7 @@ export class ScatterGLView extends Mark { this.material.defines['FAST_DRAW'] = FAST_ARROW; } if (marker === 'cross') { - this.material.uniforms.marker_scale.value = - 3 / (2 * Math.sqrt(5)); + this.material.uniforms.marker_scale.value = 3 / (2 * Math.sqrt(5)); this.material.defines['FAST_DRAW'] = FAST_CROSS; } if (marker === 'triangle-up') { @@ -937,8 +918,7 @@ export class ScatterGLView extends Mark { } updateStrokeWidth() { - this.material.uniforms.stroke_width.value = - this.model.get('stroke_width'); + this.material.uniforms.stroke_width.value = this.model.get('stroke_width'); this.updateScene(); } diff --git a/src/figure.ts b/src/figure.ts index 77fefdb..333a8ee 100644 --- a/src/figure.ts +++ b/src/figure.ts @@ -3,21 +3,17 @@ import * as THREE from 'three'; -import { - Figure, FigureModel, Mark, MarkModel -} from 'bqplot'; +import { Figure, FigureModel, Mark, MarkModel } from 'bqplot'; import { MODULE_NAME, MODULE_VERSION } from './version'; - THREE.ShaderChunk['scales'] = require('raw-loader!../shaders/scales.glsl').default; export enum ScaleType { - SCALE_TYPE_LINEAR=1, - SCALE_TYPE_LOG=2 -}; - + SCALE_TYPE_LINEAR = 1, + SCALE_TYPE_LOG = 2, +} export class FigureGLModel extends FigureModel { defaults() { @@ -28,7 +24,7 @@ export class FigureGLModel extends FigureModel { _model_module_version: FigureGLModel.model_module_version, _view_name: FigureGLModel.view_name, _view_module: FigureGLModel.view_module, - _view_module_version: FigureGLModel.view_module_version + _view_module_version: FigureGLModel.view_module_version, }; } @@ -40,7 +36,6 @@ export class FigureGLModel extends FigureModel { static view_module_version = MODULE_VERSION; } - export class FigureGLView extends Figure { private createWebGLRenderer() { // a shared webgl context for all marks diff --git a/src/plugin.ts b/src/plugin.ts index 247c7d1..699edfa 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -16,12 +16,12 @@ const EXTENSION_ID = 'bqplot-gl:plugin'; /** * The bqlotGL plugin. */ -const bqplotGLPlugin: IPlugin, void> = ({ +const bqplotGLPlugin: IPlugin, void> = { id: EXTENSION_ID, requires: [IJupyterWidgetRegistry], activate: activateWidgetExtension, autoStart: true, -} as unknown) as IPlugin, void>; +} as unknown as IPlugin, void>; // the "as unknown as ..." typecast above is solely to support JupyterLab 1 // and 2 in the same codebase and should be removed when we migrate to Lumino. diff --git a/src/values.ts b/src/values.ts index 60394e3..548f642 100644 --- a/src/values.ts +++ b/src/values.ts @@ -1,301 +1,327 @@ -import * as lodash from "lodash"; +import * as lodash from 'lodash'; import * as THREE from 'three'; import isTypedArray from 'is-typedarray'; - /* Manages a list of scalar and arrays for use with WebGL instanced rendering -*/ + */ export class Values { - constructor(names, names_vec3, getter, sequence_index, names_vec4 = []) { - this.length = Infinity; - this.scalar = {}; - this.scalar_vec3 = {}; - this.scalar_vec4 = {}; - this.array = {}; - this.array_vec3 = {}; - this.array_vec4 = {}; - this.values = {}; + constructor(names, names_vec3, getter, sequence_index, names_vec4 = []) { + this.length = Infinity; + this.scalar = {}; + this.scalar_vec3 = {}; + this.scalar_vec4 = {}; + this.array = {}; + this.array_vec3 = {}; + this.array_vec4 = {}; + this.values = {}; - // _.each(names, (name) => { - for (const name of names) { - const value = getter(name, sequence_index, this.defaults[name]); - if (isTypedArray(value)) { - if (name !== "selected") { // hardcoded.. hmm bad - this.length = Math.min(this.length, value.length); - } - this.array[name] = value; - } - else { - this.scalar[name] = value; - } - this.values[name] = value; - } - for (const name of names_vec3) { - let value = getter(name, sequence_index, this.defaults[name]); - if (name.indexOf("color") !== -1 && typeof value === "string") { - // special case to support controlling color from a widget - const color = new THREE.Color(value); - // no sequence, scalar - value = new Float32Array([color.r, color.g, color.b]); - } - if (isTypedArray(value) && value.length > 3) { - // single value is interpreted as scalar - this.array_vec3[name] = value; - this.length = Math.min(this.length, value.length / 3); - } - else { - this.scalar_vec3[name] = value; - } - this.values[name] = value; - } - for (const name of names_vec4) { - let value = getter(name, sequence_index, this.defaults[name]); - if (name.indexOf("color") !== -1 && typeof value === "string") { - // special case to support controlling color from a widget - const color = new THREE.Color(value); - value = new Float32Array([color.r, color.g, color.b, 1.0]); - } - if (isTypedArray(value) && value.length > 4) { - this.array_vec4[name] = value; - // color vectors have 4 components - this.length = Math.min(this.length, value.length / 4); - } - else { - // single value is interpreted as scalar - this.scalar_vec4[name] = value; - } - this.values[name] = value; + // _.each(names, (name) => { + for (const name of names) { + const value = getter(name, sequence_index, this.defaults[name]); + if (isTypedArray(value)) { + if (name !== 'selected') { + // hardcoded.. hmm bad + this.length = Math.min(this.length, value.length); } + this.array[name] = value; + } else { + this.scalar[name] = value; + } + this.values[name] = value; } - - trim(new_length) { - this.array = lodash.mapValues(this.array, (array) => { - return array.length === new_length ? array : array.slice(0, new_length); - }); - this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3) => { - return array_vec3.length === new_length * 3 ? array_vec3 : array_vec3.slice(0, new_length * 3); - }); - this.array_vec4 = lodash.mapValues(this.array_vec4, (array_vec4) => { - return (array_vec4.length === new_length * 4) ? array_vec4 : array_vec4.slice(0, new_length * 4); - }); - this.length = new_length; + for (const name of names_vec3) { + let value = getter(name, sequence_index, this.defaults[name]); + if (name.indexOf('color') !== -1 && typeof value === 'string') { + // special case to support controlling color from a widget + const color = new THREE.Color(value); + // no sequence, scalar + value = new Float32Array([color.r, color.g, color.b]); + } + if (isTypedArray(value) && value.length > 3) { + // single value is interpreted as scalar + this.array_vec3[name] = value; + this.length = Math.min(this.length, value.length / 3); + } else { + this.scalar_vec3[name] = value; + } + this.values[name] = value; } + for (const name of names_vec4) { + let value = getter(name, sequence_index, this.defaults[name]); + if (name.indexOf('color') !== -1 && typeof value === 'string') { + // special case to support controlling color from a widget + const color = new THREE.Color(value); + value = new Float32Array([color.r, color.g, color.b, 1.0]); + } + if (isTypedArray(value) && value.length > 4) { + this.array_vec4[name] = value; + // color vectors have 4 components + this.length = Math.min(this.length, value.length / 4); + } else { + // single value is interpreted as scalar + this.scalar_vec4[name] = value; + } + this.values[name] = value; + } + } + + trim(new_length) { + this.array = lodash.mapValues(this.array, (array) => { + return array.length === new_length ? array : array.slice(0, new_length); + }); + this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3) => { + return array_vec3.length === new_length * 3 + ? array_vec3 + : array_vec3.slice(0, new_length * 3); + }); + this.array_vec4 = lodash.mapValues(this.array_vec4, (array_vec4) => { + return array_vec4.length === new_length * 4 + ? array_vec4 + : array_vec4.slice(0, new_length * 4); + }); + this.length = new_length; + } - ensure_array(name_or_names) { - const names = lodash.isArray(name_or_names) ? name_or_names : [name_or_names]; - for (const name of names) { - if (typeof this.scalar[name] !== "undefined") { - const array = this.array[name] = new Float32Array(this.length); - array.fill(this.scalar[name]); - delete this.scalar[name]; - delete this.values[name]; - } - const value_vec3 = this.scalar_vec3[name]; - const value_vec4 = this.scalar_vec4[name]; - if (typeof value_vec3 !== "undefined") { - const array = this.array_vec3[name] = new Float32Array(this.length * 3); - for (let i = 0; i < this.length; i++) { - array[i * 3 + 0] = value_vec3[0]; - array[i * 3 + 1] = value_vec3[1]; - array[i * 3 + 2] = value_vec3[2]; - } - delete this.scalar_vec3[name]; - delete this.values[name]; - } - if (typeof value_vec4 !== "undefined") { - this.array_vec4[name] = new Float32Array(this.length * 4); - const array = this.array_vec4[name]; - for (let i = 0; i < this.length; i++) { - array[i * 4 + 0] = value_vec4[0]; - array[i * 4 + 1] = value_vec4[1]; - array[i * 4 + 2] = value_vec4[2]; - array[i * 4 + 3] = value_vec4[3]; - } - delete this.scalar_vec4[name]; - delete this.values[name]; - } + ensure_array(name_or_names) { + const names = lodash.isArray(name_or_names) + ? name_or_names + : [name_or_names]; + for (const name of names) { + if (typeof this.scalar[name] !== 'undefined') { + const array = (this.array[name] = new Float32Array(this.length)); + array.fill(this.scalar[name]); + delete this.scalar[name]; + delete this.values[name]; + } + const value_vec3 = this.scalar_vec3[name]; + const value_vec4 = this.scalar_vec4[name]; + if (typeof value_vec3 !== 'undefined') { + const array = (this.array_vec3[name] = new Float32Array( + this.length * 3 + )); + for (let i = 0; i < this.length; i++) { + array[i * 3 + 0] = value_vec3[0]; + array[i * 3 + 1] = value_vec3[1]; + array[i * 3 + 2] = value_vec3[2]; } + delete this.scalar_vec3[name]; + delete this.values[name]; + } + if (typeof value_vec4 !== 'undefined') { + this.array_vec4[name] = new Float32Array(this.length * 4); + const array = this.array_vec4[name]; + for (let i = 0; i < this.length; i++) { + array[i * 4 + 0] = value_vec4[0]; + array[i * 4 + 1] = value_vec4[1]; + array[i * 4 + 2] = value_vec4[2]; + array[i * 4 + 3] = value_vec4[3]; + } + delete this.scalar_vec4[name]; + delete this.values[name]; + } } + } - grow(new_length) { - this.array = lodash.mapValues(this.array, (array) => { - const new_array = new array.constructor(new_length); - new_array.set(array); - return new_array; - }); - this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3) => { - const new_array = new array_vec3.constructor(new_length * 3); - new_array.set(array_vec3); - return new_array; - }); - this.length = length; - } + grow(new_length) { + this.array = lodash.mapValues(this.array, (array) => { + const new_array = new array.constructor(new_length); + new_array.set(array); + return new_array; + }); + this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3) => { + const new_array = new array_vec3.constructor(new_length * 3); + new_array.set(array_vec3); + return new_array; + }); + this.length = length; + } - pad(other) { - this.array = lodash.mapValues(this.array, (array, name) => { - const new_array = new array.constructor(other.length); - if (typeof other.array[name] === "undefined") { // then other must be a scalar - new_array.fill(other.scalar[name], this.length); - } - else { - new_array.set(other.array[name].slice(this.length), this.length); - } - new_array.set(array); - return new_array; - }); - this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3, name) => { - const new_array = new array_vec3.constructor(other.length * 3); - if (typeof other.array_vec3[name] === "undefined") { // then other must be a scalar - const other_scalar = other.scalar_vec3[name]; - for (let i = this.length; i < other.length; i++) { - new_array[i * 3 + 0] = other_scalar[0]; - new_array[i * 3 + 1] = other_scalar[1]; - new_array[i * 3 + 2] = other_scalar[2]; - } - } - else { - new_array.set(other.array_vec3[name].slice(this.length * 3), this.length * 3); - } - new_array.set(array_vec3); - return new_array; - }); - this.array_vec4 = lodash.mapValues(this.array_vec4, (array_vec4, name) => { - const new_array = new array_vec4.constructor(other.length * 4); - if (typeof other.array_vec4[name] === "undefined") { - // then other must be a scalar - const other_scalar = other.scalar_vec4[name]; - for (let i = this.length; i < other.length; i++) { - new_array[i * 4 + 0] = other_scalar[0]; - new_array[i * 4 + 1] = other_scalar[1]; - new_array[i * 4 + 2] = other_scalar[2]; - new_array[i * 4 + 3] = other_scalar[3]; - } - } - else { - new_array.set(other.array_vec4[name].slice(this.length * 4), this.length * 4); - } - new_array.set(array_vec4); - return new_array; - }); - this.length = other.length; - } + pad(other) { + this.array = lodash.mapValues(this.array, (array, name) => { + const new_array = new array.constructor(other.length); + if (typeof other.array[name] === 'undefined') { + // then other must be a scalar + new_array.fill(other.scalar[name], this.length); + } else { + new_array.set(other.array[name].slice(this.length), this.length); + } + new_array.set(array); + return new_array; + }); + this.array_vec3 = lodash.mapValues(this.array_vec3, (array_vec3, name) => { + const new_array = new array_vec3.constructor(other.length * 3); + if (typeof other.array_vec3[name] === 'undefined') { + // then other must be a scalar + const other_scalar = other.scalar_vec3[name]; + for (let i = this.length; i < other.length; i++) { + new_array[i * 3 + 0] = other_scalar[0]; + new_array[i * 3 + 1] = other_scalar[1]; + new_array[i * 3 + 2] = other_scalar[2]; + } + } else { + new_array.set( + other.array_vec3[name].slice(this.length * 3), + this.length * 3 + ); + } + new_array.set(array_vec3); + return new_array; + }); + this.array_vec4 = lodash.mapValues(this.array_vec4, (array_vec4, name) => { + const new_array = new array_vec4.constructor(other.length * 4); + if (typeof other.array_vec4[name] === 'undefined') { + // then other must be a scalar + const other_scalar = other.scalar_vec4[name]; + for (let i = this.length; i < other.length; i++) { + new_array[i * 4 + 0] = other_scalar[0]; + new_array[i * 4 + 1] = other_scalar[1]; + new_array[i * 4 + 2] = other_scalar[2]; + new_array[i * 4 + 3] = other_scalar[3]; + } + } else { + new_array.set( + other.array_vec4[name].slice(this.length * 4), + this.length * 4 + ); + } + new_array.set(array_vec4); + return new_array; + }); + this.length = other.length; + } - select(selected) { - // copy since we will modify - const sizes = this.array.size = this.array.size.slice(); - const size_selected = this.array.size_selected; - // copy since we will modify - const color = this.array_vec4.color = this.array_vec4.color.slice(); - const color_selected = this.array_vec4.color_selected; - // this assumes, and requires that color_selected is an array, maybe a bit inefficient - selected.forEach((element, index) => { - if (index < this.length) { - sizes[index] = size_selected[index]; - color[index * 4 + 0] = color_selected[index * 4 + 0]; - color[index * 4 + 1] = color_selected[index * 4 + 1]; - color[index * 4 + 2] = color_selected[index * 4 + 2]; - color[index * 4 + 3] = color_selected[index * 4 + 3]; - } - }); - } + select(selected) { + // copy since we will modify + const sizes = (this.array.size = this.array.size.slice()); + const size_selected = this.array.size_selected; + // copy since we will modify + const color = (this.array_vec4.color = this.array_vec4.color.slice()); + const color_selected = this.array_vec4.color_selected; + // this assumes, and requires that color_selected is an array, maybe a bit inefficient + selected.forEach((element, index) => { + if (index < this.length) { + sizes[index] = size_selected[index]; + color[index * 4 + 0] = color_selected[index * 4 + 0]; + color[index * 4 + 1] = color_selected[index * 4 + 1]; + color[index * 4 + 2] = color_selected[index * 4 + 2]; + color[index * 4 + 3] = color_selected[index * 4 + 3]; + } + }); + } - merge_to_vec3(names, new_name) { - const element_length = names.length; - const array = new Float32Array(this.length * element_length); // Float32Array should be replaced by a good common value - names.forEach((name, index) => { - this.ensure_array(name); - const array1d = this.array[name]; - for (let i = 0; i < this.length; i++) { - array[i * element_length + index] = array1d[i]; - } - delete this.array[name]; - delete this.values[name]; - }); - this.array_vec3[new_name] = array; - } + merge_to_vec3(names, new_name) { + const element_length = names.length; + const array = new Float32Array(this.length * element_length); // Float32Array should be replaced by a good common value + names.forEach((name, index) => { + this.ensure_array(name); + const array1d = this.array[name]; + for (let i = 0; i < this.length; i++) { + array[i * element_length + index] = array1d[i]; + } + delete this.array[name]; + delete this.values[name]; + }); + this.array_vec3[new_name] = array; + } - pop(name_or_names) { - const names = lodash.isArray(name_or_names) ? name_or_names : [name_or_names]; - // _.each(names, (name) => { - names.forEach((name, index) => { - [this.scalar, - this.scalar_vec3, - this.array, - this.array_vec3].forEach((storage) => { - if (typeof storage[name] !== "undefined") { - delete storage[name]; - } - }); - }); - } + pop(name_or_names) { + const names = lodash.isArray(name_or_names) + ? name_or_names + : [name_or_names]; + // _.each(names, (name) => { + names.forEach((name, index) => { + [this.scalar, this.scalar_vec3, this.array, this.array_vec3].forEach( + (storage) => { + if (typeof storage[name] !== 'undefined') { + delete storage[name]; + } + } + ); + }); + } - add_attributes(geometry, postfix = "") { - postfix = postfix; - // set all attributes - lodash.forOwn(this.array, (array, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(array, 1, false, 1); - geometry.addAttribute(name + postfix, attr); - } - }); - lodash.forOwn(this.array_vec3, (array, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(array, 3, false, 1); - attr.normalized = name.indexOf("color") === -1 ? false : true; // color should be normalized - geometry.addAttribute(name + postfix, attr); - } - }); - lodash.forOwn(this.array_vec4, (array, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(array, 4, false, 1); - attr.normalized = name.indexOf("color") === -1 ? false : true; // color should be normalized - geometry.addAttribute(name + postfix, attr); - } - }); - lodash.forOwn(this.scalar, (scalar, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(new Float32Array([scalar]), 1, false, this.length); - geometry.addAttribute(name + postfix, attr); - } - }); - lodash.forOwn(this.scalar_vec3, (scalar_vec3, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(scalar_vec3, 3, false, this.length); - attr.normalized = name.indexOf("color") === -1 ? false : true; // color should be normalized - geometry.addAttribute(name + postfix, attr); - } - }); - lodash.forOwn(this.scalar_vec4, (scalar_vec4, name) => { - if (name.indexOf("selected") === -1) { - // selected attributes should not be send to the shader - const attr = new THREE.InstancedBufferAttribute(scalar_vec4, 4, false, this.length); - attr.normalized = name.indexOf("color") === -1 ? false : true; // color should be normalized - geometry.addAttribute(name + postfix, attr); - } - }); - } + add_attributes(geometry, postfix = '') { + postfix = postfix; + // set all attributes + lodash.forOwn(this.array, (array, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute(array, 1, false, 1); + geometry.addAttribute(name + postfix, attr); + } + }); + lodash.forOwn(this.array_vec3, (array, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute(array, 3, false, 1); + attr.normalized = name.indexOf('color') === -1 ? false : true; // color should be normalized + geometry.addAttribute(name + postfix, attr); + } + }); + lodash.forOwn(this.array_vec4, (array, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute(array, 4, false, 1); + attr.normalized = name.indexOf('color') === -1 ? false : true; // color should be normalized + geometry.addAttribute(name + postfix, attr); + } + }); + lodash.forOwn(this.scalar, (scalar, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute( + new Float32Array([scalar]), + 1, + false, + this.length + ); + geometry.addAttribute(name + postfix, attr); + } + }); + lodash.forOwn(this.scalar_vec3, (scalar_vec3, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute( + scalar_vec3, + 3, + false, + this.length + ); + attr.normalized = name.indexOf('color') === -1 ? false : true; // color should be normalized + geometry.addAttribute(name + postfix, attr); + } + }); + lodash.forOwn(this.scalar_vec4, (scalar_vec4, name) => { + if (name.indexOf('selected') === -1) { + // selected attributes should not be send to the shader + const attr = new THREE.InstancedBufferAttribute( + scalar_vec4, + 4, + false, + this.length + ); + attr.normalized = name.indexOf('color') === -1 ? false : true; // color should be normalized + geometry.addAttribute(name + postfix, attr); + } + }); + } - defaults = { - vx: 0, - vy: 1, - vz: 0, - x: 0, - y: 0, - z: 0, - size: 0, - }; + defaults = { + vx: 0, + vy: 1, + vz: 0, + x: 0, + y: 0, + z: 0, + size: 0, + }; - length: any; - scalar: any; - scalar_vec3: any; - scalar_vec4: any; - array: any; - array_vec3: any; - array_vec4: any; - values: any; + length: any; + scalar: any; + scalar_vec3: any; + scalar_vec4: any; + array: any; + array_vec3: any; + array_vec4: any; + values: any; }