diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..1e5e08b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,44 @@ +{ + "env": { + "browser": true, + "node": true, + "commonjs": true, + "es6": true + }, + "extends": "eslint:recommended", + "rules": { + "strict": 2, + "indent": 0, + "linebreak-style": 0, + "quotes": 0, + "semi": 0, + "no-cond-assign": 1, + "no-constant-condition": 1, + "no-duplicate-case": 1, + "no-empty": 1, + "no-ex-assign": 1, + "no-extra-boolean-cast": 1, + "no-extra-semi": 1, + "no-fallthrough": 1, + "no-func-assign": 1, + "no-global-assign": 1, + "no-implicit-globals": 2, + "no-inner-declarations": ["error", "functions"], + "no-irregular-whitespace": 2, + "no-loop-func": 1, + "no-magic-numbers": ["warn", { "ignore": [1, 0, -1], "ignoreArrayIndexes": true}], + "no-multi-str": 1, + "no-mixed-spaces-and-tabs": 1, + "no-proto": 1, + "no-sequences": 1, + "no-throw-literal": 1, + "no-unmodified-loop-condition": 1, + "no-useless-call": 1, + "no-void": 1, + "no-with": 2, + "wrap-iife": 1, + "no-redeclare": 1, + "no-unused-vars": ["error", { "vars": "all", "args": "none" }], + "no-sparse-arrays": 1 + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37307cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +demo +design +instances +*node_modules +*.psd +package-lock.json +docs +gh-pages +dist diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..e70af9e --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +index.html +preview.png diff --git a/index.js b/index.js new file mode 100644 index 0000000..145f14a --- /dev/null +++ b/index.js @@ -0,0 +1,42 @@ +'use strict' + + +const createScatter = reqiure('regl-scatter2d') + + +module.exports = createMatrix + + +function ReglMatrix (regl) { + // batch groups to render + this.groups = [] + + // main scatter drawing instance + this.scatter = createScatter() + + // dimensions buffer for data intersections + this.buffer = regl.buffer() +} + + +// ReglMatrix.prototype = Object.create(ReglScatter) + + +ReglMatrix.prototype.update = function (options) { + if (!options) return + + // direct points argument + if (options.length != null) { + if (typeof options[0] === 'number') options = [{positions: options}] + } + // make options a batch + else if (!Array.isArray(options)) options = [options] +} + +ReglMatrix.prototype.draw = function () { + +} + +ReglMatrix.prototype.destroy = function () { + +} diff --git a/license.md b/license.md new file mode 100644 index 0000000..87f106e --- /dev/null +++ b/license.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Dmitry Ivanov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/package.json b/package.json new file mode 100644 index 0000000..df7e396 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "regl-scattermatrix", + "version": "1.0.0", + "description": "Scatterplot matrix for 2d plots", + "main": "./index.js", + "scripts": { + "test": "budo test", + "build": "browserify test.js -g bubleify | indexhtmlify | metadataify | github-cornerify | mobilify > index.html" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dfcreative/regl-scattermatrix.git" + }, + "keywords": [ + "regl", + "plotly" + ], + "browserify": { + "transform": [ + "glslify", + "bubleify" + ] + }, + "author": "Dmitry Yv ", + "license": "MIT", + "bugs": { + "url": "https://github.com/dfcreative/regl-scattermatrix/issues" + }, + "homepage": "https://github.com/dfcreative/regl-scattermatrix#readme", + "dependencies": { + }, + "devDependencies": { + } +} diff --git a/readme.md b/readme.md index 696d9ac..e13effe 100644 --- a/readme.md +++ b/readme.md @@ -2,8 +2,8 @@ Matrix of scatter plots (SPLOM). A wrapper over [regl-scatter2d](https://github.com/dfcreative/regl-scatter2d) for optimized intersected data rendering. -* [ ] minimal GPU memory footprint (N vs N*N direct [regl-scatter2d](https://github.com/dfcreative/regl-scatter2d) case) -* [ ] optimized performance due to binary trees for 1d point clustering, opposed to default 2d quad [point-clustering](https://github.com/dfcreative/point-cluster) in regl-scatter2d. +* [x] minimal GPU memory footprint: N vs N*N in direct [regl-scatter2d](https://github.com/dfcreative/regl-scatter2d) case. +* [ ] optimized performance due to binary trees for 1d point clustering, opposed to default 2d quad clustering. ## Usage @@ -12,23 +12,43 @@ Matrix of scatter plots (SPLOM). A wrapper over [regl-scatter2d](https://github. ```js let regl = require('regl')({extensions: 'oes_element_index_uint'}) - let createMatrix = require('regl-scatter2d-matrix') let scatterMatrix = createMatrix(regl) // pass data and views to display -scatterMatrix.update({ - data: [d1, d2, ...], - view: [ - { i, j, size, color, opacity, marker, range, viewport } - ] -}) +scatterMatrix.update([ + { data: [[], [], ...], color, viewport, size, borderColor, borderWidth } +]) // draw views by ids scatterMatrix.draw(0, 1, ...views) ``` +## API + +### `splom = createSplom(regl)` + +### `splom.update(optionsA, optionsB, ...passes)` + +Define passes for `draw` method. Every options can include + +Option | Description +---|--- +`data` | An array with arrays for the columns. +`ranges` | Array with data ranges corresponding to `data`. Detected automatically. +`domains` | Array with domain ranges `[from, to]` from the `0..1` interval, defining what area of the viewport a dimension holds. +`color`, `size`, `borderColor`, `borderSize` | Points style +`viewport` | Area that the plot holds within the canvas + +### `splom.draw(...ids?)` + +Draw all defined passes, or only selected ones provided by ids. + +### `splom.destroy()` + +Dispose renderer and all the associated resources + ## Related * [regl-scatter2d](https://github.com/dfcreative/regl-scatter2d) diff --git a/test.js b/test.js new file mode 100644 index 0000000..899ba48 --- /dev/null +++ b/test.js @@ -0,0 +1,36 @@ +'use strict' + +const regl = require('regl')({ extensions: 'oes_element_index_uint'}) +const scatter = require('regl-scatter2d')(regl) +const bounds = require('array-bounds') + +const data = new Float32Array([0,.5,1,3, 4,5,6,7, 11,10,9,8]) +const buffer = regl.buffer(data) + +let w = regl._gl.drawingBufferWidth +let h = regl._gl.drawingBufferHeight +let n = 4 +let m = 3 +let iw = w / m +let ih = h / m +let passes = [] +for (let i = 0; i < m; i++) { + for (let j = 0; j < m; j++) { + let xOffset = i * n + let yOffset = j * n + let [lox, hix] = bounds(data.subarray(xOffset, xOffset + n)) + let [loy, hiy] = bounds(data.subarray(yOffset, yOffset + n)) + + passes.push({ + positions: { + x: {buffer, offset: xOffset, count: n}, + y: {buffer, offset: yOffset, count: n} + }, + bounds: [lox, loy, hix, hiy], + viewport: [i * iw, j * ih, (i + 1) * iw, (j + 1) * ih] + }) + } +} + +scatter.update(passes) +scatter.draw()