diff --git a/examples/extra-large-graphs/README.md b/examples/extra-large-graphs/README.md new file mode 100644 index 000000000..10fa4216a --- /dev/null +++ b/examples/extra-large-graphs/README.md @@ -0,0 +1,105 @@ +# Extra Large Graphs Demo with `@rapidsai/node` GPU acceleration + +RAPIDS.ai is an open source GPU-acceleration project. We're building new +tools with familiar APIs and extending existing tools so that more +scientists and users can take advantage of GPU performance. + +This project creates a `RapidsGraphologyGraph` subclass of `Graph`, +plus a modified `index.ts` to make GPU-stored graph vertices and edges +available to your browser session. It talks to the `@rapidai/demo-api-server` +that has been built using [node-rapids](https://www.github.com/rapidsai/node). + +# Performance + +Using a GPU for graph rendering offers substantial performance increases. +In this demo, I've included screenshots of performance comparisons between +using our GPU-backed `RapidsGraphologyGraph` and the original renderer +included in the `large-graphs` demo. + +When the complexity of the graph matches the original demo, performance +is comparable: + +![original size of graph, screenshot](./gpu_performance_same.png) + +When the complexity increases substantially, the GPU performance improvement +is marked: + +![size increased by 100x](./gpu_performance_two_oom_bigger.png) + +It is important to note in the larger case that the "I/O" benchmark for +the original `large-graphs` demo includes the graph generation time, which +is substantial. However, were the file stored in a 500MB .json (as in the +GPU case) and parsed in-browser, execution time is similar or longer. + +# What Is Happening + +In order to run this demo, you need the `@rapidsai/demo` npm package, +a system with a fairly modern NVIDIA GPU, and have previously installed +the [CUDA Toolkit] (https://developer.nvidia.com/cuda-toolkit). + +The node-rapids workspace [demo-api-server](https://github.com/rapidsai/node) +is available as a backend to any HTTP client. At this time only limited +functionality is available to parse JSON files in the `graphology` +graph dataset format, plus API requests to request Dataframes and +their Columns via `apache-arrow`. + +Two endpoints, `graphology/nodes` and `graphology/edges` specifically +return pre-formatted arrays that can be used directly with the +[sigma.js](https://github.com/jacomyal/sigma.js) renderer. + +## Additional Dependencies + +- @rapidsai/demo-api-server +- apache-arrow + +## To run the demo + +Due to native dependency distribution complexity, pre-packaged builds of +the node-rapids modules are presently only available via our [public docker images](https://github.com/orgs/rapidsai/packages/container/package/node). +See [USAGE.md](https://github.com/rapidsai/node/tree/main/USAGE.md) for more details. + +Generate a graph of your liking, or provide another: + +```bash +cd $SIGMAJSHOME/examples/extra-large-graphs +node generate-graph.js 10000 20000 3 graphology.json +``` + +Run `@rapidsai/demo-api-server` via docker: + +```bash +REPO=ghcr.io/rapidsai/node +VERSIONS="22.06.00-runtime-node16.15.1-cuda11.6.2-ubuntu20.04" + +# Be sure to pass either the `--runtime=nvidia` or `--gpus` flag! +docker run --rm \ + --runtime=nvidia \ + -e "DISPLAY=$DISPLAY" \ + -v "/etc/fonts:/etc/fonts:ro" \ + -v "/tmp/.X11-unix:/tmp/.X11-unix:rw" \ + -v "/usr/share/fonts:/usr/share/fonts:ro" \ + -v "/usr/share/icons:/usr/share/icons:ro" \ + -v "$(realpath -m ./graphology.json):/home/node/node_modules/@rapidsai/demo-api-server/public/graphology.json" + $REPO:$VERSIONS-demo \ + npx @rapidsai/demo-api-server +``` + +We expect to have full `npm` support soon. + +Finally run the `extra-large-graphs` demo in the normal fashion: + +```bash +cd $SIGMAJSROOT/examples +npm start --example=extra-large-graphs +``` + +## Dataset + +Run the graph generator at +to create a very large graph using the command: + +```bash +node graph-generator.js 1000000 2000000 3 graphology.json +``` +Any dataset that matches the schema of `graphology.json` is supported. + diff --git a/examples/extra-large-graphs/edge.gpu.ts b/examples/extra-large-graphs/edge.gpu.ts new file mode 100644 index 000000000..8d4c5d184 --- /dev/null +++ b/examples/extra-large-graphs/edge.gpu.ts @@ -0,0 +1,91 @@ +/** + * Sigma.js WebGL Renderer Fast Edge Program + * ========================================== + * + * Program rendering edges using GL_LINES which is presumably very fast but + * won't render thickness correctly on some GPUs and has some quirks. + * @module + */ +import { AbstractEdgeProgram } from "sigma/rendering/webgl/programs/common/edge"; +import { RenderParams } from "sigma/rendering/webgl/programs/common/program"; + +import fragmentShaderSource from "sigma/rendering/webgl/shaders/edge.fast.frag.glsl"; +import vertexShaderSource from "sigma/rendering/webgl/shaders/edge.fast.vert.glsl"; + +let POINTS = 2; +const ATTRIBUTES = 3; + +export default class EdgeGpuProgram extends AbstractEdgeProgram { + positionLocation: GLint; + colorLocation: GLint; + matrixLocation: WebGLUniformLocation; + + constructor(gl: WebGLRenderingContext) { + super(gl, vertexShaderSource, fragmentShaderSource, POINTS, ATTRIBUTES); + + // Locations: + this.positionLocation = gl.getAttribLocation(this.program, "a_position"); + this.colorLocation = gl.getAttribLocation(this.program, "a_color"); + + // Uniform locations: + const matrixLocation = gl.getUniformLocation(this.program, "u_matrix"); + if (matrixLocation === null) throw new Error("EdgeGpuProgram: error while getting matrixLocation"); + this.matrixLocation = matrixLocation; + + this.bind(); + } + + bind(): void { + const gl = this.gl; + + // Bindings + gl.enableVertexAttribArray(this.positionLocation); + gl.enableVertexAttribArray(this.colorLocation); + + gl.vertexAttribPointer( + this.positionLocation, + 2, + gl.FLOAT, + false, + this.attributes * Float32Array.BYTES_PER_ELEMENT, + 0, + ); + gl.vertexAttribPointer( + this.colorLocation, + 4, + gl.UNSIGNED_BYTE, + true, + this.attributes * Float32Array.BYTES_PER_ELEMENT, + 8, + ); + } + + computeIndices(): void { + //nothing to do + } + + process( + sourceData, + targetData, + data, + hidden: boolean, + offset: number, + ): void { + this.array = data.buffer.getChild('edges').toArray(); + POINTS = this.array.length / ATTRIBUTES; + this.points = POINTS; + } + + render(params: RenderParams): void { + if (this.hasNothingToRender()) return; + + const gl = this.gl; + const program = this.program; + + gl.useProgram(program); + + gl.uniformMatrix3fv(this.matrixLocation, false, params.matrix); + + gl.drawArrays(gl.LINES, 0, this.array.length / ATTRIBUTES); + } +} diff --git a/examples/extra-large-graphs/generate-graph.js b/examples/extra-large-graphs/generate-graph.js new file mode 100755 index 000000000..d57a6e48c --- /dev/null +++ b/examples/extra-large-graphs/generate-graph.js @@ -0,0 +1,69 @@ +const fs = require('fs'); +const seedrandom = require('seedrandom'); + +const {Graph} = require('graphology'); + +const circlepack = require( 'graphology-layout/circlepack'); +const clusters = require( 'graphology-generators/random/clusters'); + +try { + const args = process.argv.slice(2); + const order = Number(args[0]); + const size = Number(args[1]); + const num_clusters = Number(args[2]); + const outputName = args[3]; + const rng = seedrandom('sigma'); + const state = { + size: size, + order: order, + clusters: num_clusters, + edgesRenderer: 'edges-fast' + }; + + // 1. Generate a graph: + const graph = clusters(Graph, { ...state, rng }); + circlepack.assign(graph, { + hierarchyAttributes: ['cluster'], + }); + const colors = {}; + for (let i = 0; i < +state.clusters; i++) { + colors[i] = '#' + Math.floor(rng() * 16777215).toString(16); + } + let i = 0; + graph.forEachNode((node, { cluster }) => { + graph.mergeNodeAttributes(node, { + size: graph.degree(node) > 1 ? graph.degree(node) / 2 : 1, + label: `Node n°${++i}, in cluster n°${cluster}`, + color: colors[cluster + ''], + }); + }); + + // 2. Save the graph: + fs.writeFileSync(outputName, JSON.stringify(graph.toJSON(), {}, 2), (err) => { + if(err) { + console.log('unable to save file'); + } else { + console.log('file saved'); + } + }); + console.log('Graph Generated.'); + console.log('You must copy the output file to'); + console.log(''); + console.log('node/modules/demo/api-server/routes/public/graphology.json'); + console.log('to use with node-rapids/demo-api-server'); + console.log('and sigma.js/examples/extra-large-graph'); +} +catch (e) { + console.log('Exception'); + console.log(e); + console.log(''); + console.log('generate-graph.js usage:'); + console.log('------------------------'); + console.log(''); + console.log('node generate-graph.js '); + console.log(''); + console.log('example: '); + console.log('node generate-graph.js 2000000 1000000 3 graphology.json'); + console.log(''); +} + diff --git a/examples/extra-large-graphs/gpu-loader.ts b/examples/extra-large-graphs/gpu-loader.ts new file mode 100644 index 000000000..1897981cd --- /dev/null +++ b/examples/extra-large-graphs/gpu-loader.ts @@ -0,0 +1,61 @@ +/** + * This example aims at showcasing sigma's performances. + */ + +import arrow from 'apache-arrow'; + +async function request(obj) { + return new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); + xhr.open(obj.method || 'GET', obj.url || obj); + if (obj.headers) { + Object.keys(obj.headers).forEach(key => { xhr.setRequestHeader(key, obj.headers[key]); }); + } + xhr.onload = () => { + try { + if (xhr.status >= 200 && xhr.status < 300) { + resolve(xhr.response); + } else { + reject(xhr.statusText); + } + } catch (e) { reject(e); } + }; + xhr.onerror = () => reject(xhr.statusText); + xhr.send(obj.body); + }); +} + +const SERVER = 'http://localhost:3010'; +const DATASET_ROUTE = '/graphology/read_large_demo?filename=../../public/graphology.json'; +const NODES_ROUTE = '/graphology/get_column/nodes'; +const NODES_BOUNDS_ROUTE = '/graphology/nodes/bounds'; +const NODES_BUFFER_ROUTE = '/graphology/nodes'; +const EDGES_BUFFER_ROUTE = '/graphology/edges'; +const TABLE_ROUTE = '/graphology/get_table'; + +const GpuLoader = { + init: async () => request({method: 'POST', url: SERVER + DATASET_ROUTE, mode: 'no-cors'}), + getTable: async (table) => { + const result = await fetch(SERVER + TABLE_ROUTE + '/' + table, {method: 'GET', headers: {'Access-Control-Allow-Origin': '*'}}) + return arrow.tableFromIPC(result); + }, + getColumn: async (table, column) => { + const table_route = {'nodes': '/graphology/get_column/nodes/'}[table]; + const column_route = SERVER + table_route + column; + const result = await fetch(column_route, {method: 'GET', headers: {'Access-Control-Allow-Origin': '*'}}); + return arrow.tableFromIPC(result); + }, + getNodesBounds: async () => request(SERVER + NODES_BOUNDS_ROUTE), + getNodesBuffer: async () => { + const route = SERVER + NODES_BUFFER_ROUTE; + const result = await fetch(route, {method: 'GET', headers: {'Access-Control-Allow-Origin': '*'}}); + return arrow.tableFromIPC(result); + }, + getEdgesBuffer: async () => { + const route = SERVER + EDGES_BUFFER_ROUTE; + const result = await fetch(route, {method: 'GET', headers: {'Access-Control-Allow-Origin': '*'}}); + return arrow.tableFromIPC(result); + } +}; + +export default GpuLoader; diff --git a/examples/extra-large-graphs/gpu_performance_same.png b/examples/extra-large-graphs/gpu_performance_same.png new file mode 100644 index 000000000..8b1db122c Binary files /dev/null and b/examples/extra-large-graphs/gpu_performance_same.png differ diff --git a/examples/extra-large-graphs/gpu_performance_two_oom_bigger.png b/examples/extra-large-graphs/gpu_performance_two_oom_bigger.png new file mode 100644 index 000000000..173d8fbe3 Binary files /dev/null and b/examples/extra-large-graphs/gpu_performance_two_oom_bigger.png differ diff --git a/examples/extra-large-graphs/index.html b/examples/extra-large-graphs/index.html new file mode 100644 index 000000000..6ab673d12 --- /dev/null +++ b/examples/extra-large-graphs/index.html @@ -0,0 +1,153 @@ + + + + + + + Sigma example: GPU Performances showcase + + + +
Sigma example: GPU Performance showcase
+
+
+
+
+

Gpu Graph

+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

Host Graph

+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+

Graph

+
+ + +
+
+ + +
+
+ + +
+
+
+

Edges renderer

+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + + diff --git a/examples/extra-large-graphs/index.ts b/examples/extra-large-graphs/index.ts new file mode 100644 index 000000000..75b470663 --- /dev/null +++ b/examples/extra-large-graphs/index.ts @@ -0,0 +1,153 @@ +/** + * NVIDIA 2022 (c) + * This example aims at showcasing sigma's performances. + */ + +import {Table} from 'apache-arrow'; +import Sigma from 'sigma'; +import Graph from 'graphology'; + +import EdgesGpuProgram from './edge.gpu'; +import gpuLoader from './gpu-loader'; +import NodesGpuProgram from './node.gpu'; +import RapidsGraphologyGraph from './rapids-graph' + +import EdgesDefaultProgram from "sigma/rendering/webgl/programs/edge"; +import EdgesFastProgram from "sigma/rendering/webgl/programs/edge.fast"; + +import circlepack from "graphology-layout/circlepack"; +import clusters from "graphology-generators/random/clusters"; + +import seedrandom from "seedrandom"; +const rng = seedrandom("sigma"); + +// node-rapids demo for sigma.js +(async function() { + await (async function() { + console.log('extra-large-graphs'); + + // Load the graph via node-rapids. It will be resident on your + // local GPU. + const t0 = performance.now(); + await gpuLoader.init(); + const bounds = await gpuLoader.getNodesBounds(); + const nodes = await gpuLoader.getNodesBuffer(); + const edges = await gpuLoader.getEdgesBuffer(); + const options = await gpuLoader.getTable('options'); + const graph = new RapidsGraphologyGraph(nodes, edges, options); + graph.setExtent(JSON.parse(bounds.toString()).bounds); + const t1 = performance.now(); + const ioTime = t1 - t0; + + // Render the graph: + const container = document.getElementById('sigma-gpu-container') as HTMLElement; + const t2 = performance.now(); + const renderer = new Sigma(graph, container, { + defaultEdgeColor: '#e6e6e6', + defaultEdgeType: 'edges-fast', + edgeProgramClasses: { + 'edges-fast': EdgesGpuProgram, + }, + nodeProgramClasses: { + 'circle': NodesGpuProgram, + }, + }); + const t3 = performance.now(); + const renderTime = t3 - t2; + + const updateFields = () => { + const orderField = document.getElementById('order_gpu') as HTMLDivElement; + orderField.innerHTML = String(nodes.numRows / 4); + const sizeField = document.getElementById('size_gpu') as HTMLDivElement; + sizeField.innerHTML = String(edges.numRows / 6); + const ioTimeField = document.getElementById('io_time_gpu') as HTMLDivElement; + ioTimeField.innerHTML = String(ioTime) + ' msec'; + const renderTimeField = document.getElementById('render_time_gpu') as HTMLDivElement; + renderTimeField.innerHTML = String(renderTime) + ' msec'; + }; + + setTimeout(() => { + updateFields(); + }, 100); + })(); + + // Original demo, plus performance measures + + await (async function() { + console.log('large-graphs'); + + // 1. Read query string, and set form values accordingly: + const query = new URLSearchParams(location.search).entries(); + for (const [key, value] of query) { + const domList = document.getElementsByName(key); + if (domList.length === 1) { + (domList[0] as HTMLInputElement).value = value; + } else if (domList.length > 1) { + domList.forEach((dom: HTMLElement) => { + const input = dom as HTMLInputElement; + input.value = value; + input.checked = input.value === value; + }); + } + } + + // 2. Read form values to build a full state: + const state = { + order: +document.querySelector("#order")?.value, + size: +document.querySelector("#size")?.value, + clusters: +document.querySelector("#clusters")?.value, + edgesRenderer: document.querySelector('[name="edges-renderer"]:checked')?.value, + }; + + const t0 = performance.now(); + // 3. Generate a graph: + const graph = clusters(Graph, { ...state, rng }); + circlepack.assign(graph, { + hierarchyAttributes: ["cluster"], + }); + const colors: Record = {}; + for (let i = 0; i < +state.clusters; i++) { + colors[i] = "#" + Math.floor(rng() * 16777215).toString(16); + } + let i = 0; + graph.forEachNode((node, { cluster }) => { + graph.mergeNodeAttributes(node, { + size: graph.degree(node) / 3, + label: `Node n°${++i}, in cluster n°${cluster}`, + color: colors[cluster + ""], + }); + }); + const t1 = performance.now(); + const generateTime = t1 - t0; + + // 4. Render the graph: + const t2 = performance.now(); + const container = document.getElementById("sigma-container") as HTMLElement; + const renderer = new Sigma(graph, container, { + defaultEdgeColor: "#e6e6e6", + defaultEdgeType: state.edgesRenderer, + edgeProgramClasses: { + "edges-default": EdgesDefaultProgram, + "edges-fast": EdgesFastProgram, + }, + }); + const t3 = performance.now(); + const renderTimeHost = t3 - t2; + + // Cheap trick: tilt the camera a bit to make labels more readable: + renderer.getCamera().setState({ + angle: 0.2, + }); + + const updateFieldsHost = () => { + const ioTimeField = document.getElementById('io_time_host') as HTMLDivElement; + ioTimeField.innerHTML = String(generateTime) + ' msec'; + const renderTimeField = document.getElementById('render_time_host') as HTMLDivElement; + renderTimeField.innerHTML = String(renderTimeHost) + ' msec'; + }; + + setTimeout(() => { + updateFieldsHost(); + }, 100); + })(); +})(); diff --git a/examples/extra-large-graphs/node.gpu.ts b/examples/extra-large-graphs/node.gpu.ts new file mode 100644 index 000000000..ade052535 --- /dev/null +++ b/examples/extra-large-graphs/node.gpu.ts @@ -0,0 +1,45 @@ +/** + * Sigma.js WebGL Renderer Node Program + * ===================================== + * + * Simple program rendering nodes using GL_POINTS. This is faster than the + * three triangle option but has some quirks and is not supported equally by + * every GPU. + * @module + */ +import {AbstractNodeProgram} from 'sigma/rendering/webgl/programs/common/node'; +import {RenderParams} from 'sigma/rendering/webgl/programs/common/program'; + +import fragmentShaderSource from 'sigma/rendering/webgl/shaders/node.fast.frag.glsl'; +import vertexShaderSource from 'sigma/rendering/webgl/shaders/node.fast.vert.glsl'; + +let POINTS = 1; +const ATTRIBUTES = 4; + +export default class NodeGpuProgram extends AbstractNodeProgram { + constructor(gl: WebGLRenderingContext) { + super(gl, vertexShaderSource, fragmentShaderSource, POINTS, ATTRIBUTES); + this.bind(); + } + + process(data, hidden: boolean, offset: number): void { + this.array = data.buffer.getChild('nodes').toArray(); + POINTS = this.array.length / ATTRIBUTES; + this.points = POINTS; + } + + render(params: RenderParams): void { + if (this.hasNothingToRender()) return; + + const gl = this.gl; + + const program = this.program; + gl.useProgram(program); + + gl.uniform1f(this.ratioLocation, 1 / Math.sqrt(params.ratio)); + gl.uniform1f(this.scaleLocation, params.scalingRatio); + gl.uniformMatrix3fv(this.matrixLocation, false, params.matrix); + + gl.drawArrays(gl.POINTS, 0, this.array.length / ATTRIBUTES); + } +} diff --git a/examples/extra-large-graphs/package.json b/examples/extra-large-graphs/package.json new file mode 100644 index 000000000..71042f03a --- /dev/null +++ b/examples/extra-large-graphs/package.json @@ -0,0 +1,24 @@ +{ + "name": "sigma-example-extra-large-graphs", + "version": "1.0.0", + "description": "A sigma example to showcase node/rapids performances.", + "main": "index.js", + "scripts": { + "start": "kotatsu --port 3001 serve --typescript index.ts --public / ./public" + }, + "license": "MIT", + "dependencies": { + "@types/seedrandom": "^3.0.1", + "apache-arrow": "8.0.0", + "graphology": "^0.23.0", + "graphology-generators": "^0.11.2", + "graphology-layout": "^0.5.0", + "graphology-layout-forceatlas2": "^0.8.1", + "graphology-types": "^0.23.0", + "seedrandom": "^3.0.5", + "sigma": "latest" + }, + "devDependencies": { + "kotatsu": "^0.22.3" + } +} \ No newline at end of file diff --git a/examples/extra-large-graphs/rapids-graph.ts b/examples/extra-large-graphs/rapids-graph.ts new file mode 100644 index 000000000..07017a434 --- /dev/null +++ b/examples/extra-large-graphs/rapids-graph.ts @@ -0,0 +1,90 @@ +// NVIDIA 2022 + +import {Table} from 'apache-arrow'; +import Graph, {InvalidArgumentsGraphError} from 'graphology'; +import assignPolyfill from 'graphology'; + +/** + * RapidsGraphologyGraph subclasses the Graph class of graphology + * for compatibility with the node and edge processing and + * rendering functions of sigma.js. + * + * Elements in sigma.js depend upon iterating over the nodes + * and edges of the graphology Graph object. RapidsGraphologyGraph + * shortcuts these functions, providing mock data in order to trick + * the iterator where necessary, and providing GPU computed bounds + * values to sigma.js where appropriate + */ +export default class RapidsGraphologyGraph extends Graph { + _gpu_nodes: Table; + _gpu_edges: Table; + _gpu_options: Table; + _the_node: Map; + _nodeExtent: Map; + + constructor(nodes: Table, edges: Table, options: Table) { + super(new Graph({type: 'undirected'})); // filler, not supported types of graphs yet + this._nodeExtent = new Map(); + this._gpu_nodes = nodes; + this._gpu_edges = edges; + this._gpu_options = options; + + // this._the_node contains metadata essential to sigma.js, usually obtained + // from each individual Graph container. A single node is provided to allow + // sigma.js to continue processing with the necessary data. + this._the_node = new Map(); + this._the_node['node'] = null; + this._the_node['hidden'] = false; // hidden is not supported yet in this example. + + // Graphology Graph objects must provide the following members in order to + // configure sigma.js. Instead of trying to override or properly subclass the + // parent methods, I just overwrite them here. + Object.defineProperty(this, 'order', {value: this._gpu_nodes.numRows}); + Object.defineProperty(this, 'nodeExtent', {value: {x: [0, 5], y: [5, 10]}}); + Object.defineProperty(this, 'nodes', {value: () => { + this._the_node['node'] = this._gpu_nodes; + return [this._the_node]; + }}); + // sigma.js pulls all of the values of a node from a Graph as it iterates over them. + // In the GPU-backed example, all of the node coordinates and attributes are pre- + // computed. + Object.defineProperty(this, 'getNodeAttributes', { + value: () => { + return { 'buffer': this._gpu_nodes, 'x': -1, 'y': -1 } + } + }); + + // edges do not depend on as much metadata. + Object.defineProperty(this, 'edges', {value: () => { return [{'edge': this._gpu_edges}] }}); + // As in the above nodes, all edges metadata is precomputed on the GPU. Included + // attributes other than "buffer" are provided to trick the iterator and renderer. + Object.defineProperty(this, 'getEdgeAttributes', { + value: () => { + return { 'buffer': this._gpu_edges, 'source': -1, 'target': -1, color: '#999', hidden: false } + } + }); + + // Placeholder + Object.defineProperty(this, 'extremities', { + value: () => { + return [this._the_node, this._the_node] + } + }); + + // The forEachNode iterator simply returns a single pair. + Object.defineProperty(this, 'forEachNode', { + value: (callback) => { + if (typeof callback != 'function') + throw new InvalidArgumentsGraphError( + 'RapidsGraphologyGraph.forEachNode: expecting a callback'); + const p1 = {x: this._nodeExtent['xmin'], y: this._nodeExtent['ymin']}; + const p2 = {x: this._nodeExtent['xmax'], y: this._nodeExtent['ymax']}; + callback('gpu_nodes_p1', p1); + callback('gpu_nodes_p2', p2); + } + }); + } + + // A real accessor! Extent is received from an HTTP request and set normally. + setExtent(bounds) { this._nodeExtent = bounds; } +} diff --git a/examples/extra-large-graphs/sandbox.config.json b/examples/extra-large-graphs/sandbox.config.json new file mode 100644 index 000000000..33673fa1c --- /dev/null +++ b/examples/extra-large-graphs/sandbox.config.json @@ -0,0 +1,6 @@ +{ + "infiniteLoopProtection": true, + "hardReloadOnChange": false, + "view": "browser", + "template": "create-react-app" +} diff --git a/examples/large-graphs/index.ts b/examples/large-graphs/index.ts index e0e1dbdcd..d4c2625d2 100644 --- a/examples/large-graphs/index.ts +++ b/examples/large-graphs/index.ts @@ -55,6 +55,7 @@ graph.forEachNode((node, { cluster }) => { color: colors[cluster + ""], }); }); +console.log(graph); // 4. Render the graph: const container = document.getElementById("sigma-container") as HTMLElement; diff --git a/examples/package-lock.json b/examples/package-lock.json index 0045e7afa..eeb0b4864 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -12,6 +12,7 @@ "@types/file-saver": "^2.0.4", "@types/papaparse": "^5.3.1", "@types/seedrandom": "^3.0.1", + "apache-arrow": "8.0.0", "chroma-js": "^2.1.2", "file-saver": "^2.0.5", "graphology": "^0.23.2", @@ -1755,6 +1756,16 @@ "node": ">=6.9.0" } }, + "node_modules/@types/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==" + }, + "node_modules/@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==" + }, "node_modules/@types/eslint": { "version": "7.28.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz", @@ -1786,6 +1797,11 @@ "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.4.tgz", "integrity": "sha512-sPZYQEIF/SOnLAvaz9lTuydniP+afBMtElRTdYkeV1QtEgvtJ7qolCPjly6O32QI8CbEmP5O/fztMXEDWfEcrg==" }, + "node_modules/@types/flatbuffers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", + "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" + }, "node_modules/@types/http-proxy": { "version": "1.17.7", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz", @@ -1802,9 +1818,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz", - "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==" + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/@types/pad-left": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/pad-left/-/pad-left-2.1.1.tgz", + "integrity": "sha512-Xd22WCRBydkGSApl5Bw0PhAOHKSVjNL3E3AwzKaps96IMraPqy5BvZIsBVK6JLwdybUzjHnuWVwpDd0JjTfHXA==" }, "node_modules/@types/papaparse": { "version": "5.3.1", @@ -2085,6 +2106,35 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/apache-arrow": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-8.0.0.tgz", + "integrity": "sha512-74wgHL9P+vgylNOhnLGw1meOQ1cbYyi+TXo1eDnQJ9g2Ly+k8novUWQIG5SIp6acnErhGRTsMJajwUh9x/ZbaQ==", + "dependencies": { + "@types/command-line-args": "5.2.0", + "@types/command-line-usage": "5.0.2", + "@types/flatbuffers": "*", + "@types/node": "^17.0.24", + "@types/pad-left": "2.1.1", + "command-line-args": "5.2.1", + "command-line-usage": "6.1.3", + "flatbuffers": "2.0.4", + "json-bignum": "^0.0.3", + "pad-left": "^2.1.0", + "tslib": "^2.3.1" + }, + "bin": { + "arrow2csv": "bin/arrow2csv.js" + } + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -2470,6 +2520,106 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -2701,6 +2851,14 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -2811,7 +2969,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -3023,6 +3180,17 @@ "node": ">=6" } }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -3035,6 +3203,11 @@ "node": ">=6" } }, + "node_modules/flatbuffers": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-2.0.4.tgz", + "integrity": "sha512-4rUFVDPjSoP0tOII34oQf+72NKU7E088U5oX7kwICahft0UB2kOQ9wUzzCp+OHxByERIfxRDCgX5mP8Pjkfl0g==" + }, "node_modules/follow-redirects": { "version": "1.14.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", @@ -3628,6 +3801,14 @@ "node": ">=4" } }, + "node_modules/json-bignum": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", + "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -3777,6 +3958,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -4094,6 +4280,17 @@ "node": ">=6" } }, + "node_modules/pad-left": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", + "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", + "dependencies": { + "repeat-string": "^1.5.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pandemonium": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/pandemonium/-/pandemonium-1.5.0.tgz", @@ -4457,6 +4654,14 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "engines": { + "node": ">=6" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -4534,6 +4739,14 @@ "jsesc": "bin/jsesc" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4870,6 +5083,36 @@ "node": ">=8" } }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -5030,6 +5273,11 @@ "node": ">=10" } }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -5056,6 +5304,14 @@ "node": ">=4.2.0" } }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "engines": { + "node": ">=8" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -5318,6 +5574,26 @@ "node": ">= 8" } }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -6589,6 +6865,16 @@ "to-fast-properties": "^2.0.0" } }, + "@types/command-line-args": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", + "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==" + }, + "@types/command-line-usage": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", + "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==" + }, "@types/eslint": { "version": "7.28.2", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz", @@ -6620,6 +6906,11 @@ "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.4.tgz", "integrity": "sha512-sPZYQEIF/SOnLAvaz9lTuydniP+afBMtElRTdYkeV1QtEgvtJ7qolCPjly6O32QI8CbEmP5O/fztMXEDWfEcrg==" }, + "@types/flatbuffers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@types/flatbuffers/-/flatbuffers-1.10.0.tgz", + "integrity": "sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==" + }, "@types/http-proxy": { "version": "1.17.7", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz", @@ -6636,9 +6927,14 @@ "dev": true }, "@types/node": { - "version": "16.11.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz", - "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==" + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "@types/pad-left": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/pad-left/-/pad-left-2.1.1.tgz", + "integrity": "sha512-Xd22WCRBydkGSApl5Bw0PhAOHKSVjNL3E3AwzKaps96IMraPqy5BvZIsBVK6JLwdybUzjHnuWVwpDd0JjTfHXA==" }, "@types/papaparse": { "version": "5.3.1", @@ -6884,6 +7180,29 @@ "color-convert": "^2.0.1" } }, + "apache-arrow": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-8.0.0.tgz", + "integrity": "sha512-74wgHL9P+vgylNOhnLGw1meOQ1cbYyi+TXo1eDnQJ9g2Ly+k8novUWQIG5SIp6acnErhGRTsMJajwUh9x/ZbaQ==", + "requires": { + "@types/command-line-args": "5.2.0", + "@types/command-line-usage": "5.0.2", + "@types/flatbuffers": "*", + "@types/node": "^17.0.24", + "@types/pad-left": "2.1.1", + "command-line-args": "5.2.1", + "command-line-usage": "6.1.3", + "flatbuffers": "2.0.4", + "json-bignum": "^0.0.3", + "pad-left": "^2.1.0", + "tslib": "^2.3.1" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -7186,6 +7505,84 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "requires": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -7352,6 +7749,11 @@ "ms": "2.1.2" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7440,8 +7842,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint-scope": { "version": "5.1.1", @@ -7623,6 +8024,14 @@ "pkg-dir": "^3.0.0" } }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -7632,6 +8041,11 @@ "locate-path": "^3.0.0" } }, + "flatbuffers": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-2.0.4.tgz", + "integrity": "sha512-4rUFVDPjSoP0tOII34oQf+72NKU7E088U5oX7kwICahft0UB2kOQ9wUzzCp+OHxByERIfxRDCgX5mP8Pjkfl0g==" + }, "follow-redirects": { "version": "1.14.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", @@ -8065,6 +8479,11 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-bignum": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", + "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==" + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -8187,6 +8606,11 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -8425,6 +8849,14 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "pad-left": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", + "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", + "requires": { + "repeat-string": "^1.5.4" + } + }, "pandemonium": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/pandemonium/-/pandemonium-1.5.0.tgz", @@ -8679,6 +9111,11 @@ } } }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==" + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -8746,6 +9183,11 @@ } } }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8994,6 +9436,29 @@ "has-flag": "^4.0.0" } }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==" + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -9095,6 +9560,11 @@ } } }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -9111,6 +9581,11 @@ "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "dev": true }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -9296,6 +9771,22 @@ "isexe": "^2.0.0" } }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==" + } + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/examples/package.json b/examples/package.json index ed4c88150..f7cb64f52 100644 --- a/examples/package.json +++ b/examples/package.json @@ -16,6 +16,7 @@ "@types/file-saver": "^2.0.4", "@types/papaparse": "^5.3.1", "@types/seedrandom": "^3.0.1", + "apache-arrow": "8.0.0", "chroma-js": "^2.1.2", "file-saver": "^2.0.5", "graphology": "^0.23.2", diff --git a/examples/webpack.config.js b/examples/webpack.config.js index b34b7f80f..199479707 100644 --- a/examples/webpack.config.js +++ b/examples/webpack.config.js @@ -20,9 +20,22 @@ module.exports = { __dirname, "../src/rendering/webgl/programs/common/node.ts", ), + "sigma/rendering/webgl/programs/common/edge": path.resolve( + __dirname, + "../src/rendering/webgl/programs/common/edge.ts", + ), + "sigma/rendering/webgl/programs/common/edge.fast.frag.glsl": path.resolve( + __dirname, + "../src/rendering/webgl/programs/common/edge.fast.frag.glsl", + ), + "sigma/rendering/webgl/shaders": path.resolve( + __dirname, + "../src/rendering/webgl/shaders/", + ), sigma: path.resolve(__dirname, "../src/index.ts"), - }, - }, + "apache-arrow": require.resolve("apache-arrow/Arrow.es2015.min") + } +}, module: { rules: [ {