├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── shaders ├── draw_dots.fs.glsl └── draw_dots.vs.glsl /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jim Vallandingham 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # regl explore 2 | 3 | Small starter kit for exploring [regl](https://github.com/regl-project/regl) 4 | 5 | Read more: [Intro to regl for Data Visualization](http://vallandingham.me/regl_intro.html) 6 | 7 | ## Use 8 | 9 | Initial setup uses npm to install dependencies: 10 | 11 | ``` 12 | npm install 13 | ``` 14 | 15 | Then you can just: 16 | 17 | ``` 18 | npm start 19 | ``` 20 | 21 | ## Features 22 | 23 | Includes 24 | 25 | * regl 26 | * browserify 27 | * glslify 28 | * budo 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | const regl = require('regl')(); 3 | const glslify = require('glslify'); 4 | 5 | // Helper function to create a random float between 6 | // some defined range. This is used to create some 7 | // fake data. In a real setting, you would probably 8 | // use D3 to map data to display coordinates. 9 | function randomFromInterval(min, max) { 10 | return Math.random() * (max - min + 1) + min; 11 | } 12 | 13 | // Helper function to create a random integer between 14 | // some defined range. Again, you would want to use 15 | // D3 for mapping real data to display coordinates. 16 | function randomIntFromInterval(min, max) { 17 | return Math.floor(randomFromInterval(min, max)); 18 | } 19 | 20 | // Some constants to use 21 | var MAX_WIDTH = 2000; 22 | var MAX_HEIGHT = 800; 23 | var MAX_SPEED = 25; 24 | var POINT_SIZE = 10; 25 | var POINT_COUNT = 400; 26 | 27 | 28 | // Helper function to generate some fake data. 29 | // Each data point has an x and y and a 'speed' 30 | // value that indicates how fast it travels 31 | function createData(dataCount) { 32 | var data = []; 33 | for(var i = 0; i < dataCount; i++) { 34 | var datum = { 35 | id: i, 36 | speed: randomFromInterval(1, MAX_SPEED), 37 | y: randomIntFromInterval(POINT_SIZE, MAX_HEIGHT), 38 | x: 0, 39 | size: randomIntFromInterval(POINT_SIZE, POINT_SIZE * 3), 40 | }; 41 | 42 | data.push(datum); 43 | } 44 | return data; 45 | } 46 | 47 | // Helper function, goes through each 48 | // element in the fake data and updates 49 | // its x position. 50 | function updateData(data) { 51 | data.forEach(function(datum) { 52 | datum.x += datum.speed 53 | // reset x if its gone past max width 54 | datum.x = datum.x > MAX_WIDTH ? 0 : datum.x; 55 | }); 56 | } 57 | 58 | const drawDots = regl({ 59 | 60 | // use glslify to import shader code! 61 | frag: glslify('./shaders/draw_dots.fs.glsl'), 62 | vert: glslify('./shaders/draw_dots.vs.glsl'), 63 | 64 | attributes: { 65 | // There will be a position value for each point 66 | // we pass in 67 | position: function(context, props) { 68 | return props.points.map(function(point) { 69 | return [point.x, point.y] 70 | }); 71 | }, 72 | // Now pointWidth is an attribute, as each 73 | // point will have a different size. 74 | pointWidth: function(context, props) { 75 | return props.points.map(function(point) { 76 | return point.size; 77 | }); 78 | }, 79 | }, 80 | 81 | uniforms: { 82 | color: function(context, props) { 83 | // just to be a bit strange, oscillate the color a bit. 84 | return [Math.cos(context.tick / 100), 0.304, 1.000, 1.000]; 85 | }, 86 | // FYI: there is a helper method for grabbing 87 | // values out of the context as well. 88 | // These uniforms are used in our fragment shader to 89 | // convert our x / y values to WebGL coordinate space. 90 | stageWidth: regl.context('drawingBufferWidth'), 91 | stageHeight: regl.context('drawingBufferHeight') 92 | }, 93 | 94 | count: function(context, props) { 95 | // set the count based on the number of points we have 96 | return props.points.length 97 | }, 98 | primitive: 'points' 99 | 100 | }) 101 | 102 | var points = createData(POINT_COUNT); 103 | 104 | regl.frame(function(context) { 105 | // Each loop, update the data 106 | updateData(points); 107 | 108 | // And draw it! 109 | drawDots({ 110 | pointWidth: POINT_SIZE, 111 | points: points 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regl_explore", 3 | "version": "0.0.1", 4 | "description": "a starting point to explore regl with!", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "budo index.js --open --live", 8 | "build": "browserify index.js -t es2040 | indexhtmlify > index.html" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/vlandham/regl_explore.git" 13 | }, 14 | "keywords": [ 15 | "regl", 16 | "webgl" 17 | ], 18 | "author": "Jim Vallandingham (http://vallandingham.me/)", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/vlandham/regl_explore/issues" 22 | }, 23 | "homepage": "https://github.com/vlandham/regl_explore#readme", 24 | "browserify": { 25 | "transform": [ 26 | "glslify" 27 | ] 28 | }, 29 | "devDependencies": { 30 | "browserify": "^14.3.0", 31 | "budo": "^10.0.3", 32 | "glslify": "^6.0.2" 33 | }, 34 | "dependencies": { 35 | "regl": "^1.3.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /shaders/draw_dots.fs.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform vec4 color; 3 | void main () { 4 | gl_FragColor = color; 5 | } 6 | -------------------------------------------------------------------------------- /shaders/draw_dots.vs.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | attribute vec2 position; 3 | attribute float pointWidth; 4 | 5 | uniform float stageWidth; 6 | uniform float stageHeight; 7 | 8 | // helper function to transform from pixel space to normalized 9 | // device coordinates (NDC). In NDC (0,0) is the middle, 10 | // (-1, -1) is the top left and (1, 1) is the bottom right. 11 | // Stolen from Peter Beshai's great blog post: 12 | // http://peterbeshai.com/beautifully-animate-points-with-webgl-and-regl.html 13 | vec2 normalizeCoords(vec2 position) { 14 | // read in the positions into x and y vars 15 | float x = position[0]; 16 | float y = position[1]; 17 | 18 | return vec2( 19 | 2.0 * ((x / stageWidth) - 0.5), 20 | // invert y to treat [0,0] as bottom left in pixel space 21 | -(2.0 * ((y / stageHeight) - 0.5))); 22 | } 23 | 24 | void main () { 25 | gl_PointSize = pointWidth; 26 | gl_Position = vec4(normalizeCoords(position), 0, 1); 27 | } 28 | --------------------------------------------------------------------------------