Skip to content

Commit

Permalink
Merge pull request #15 from bpostlethwaite/updates
Browse files Browse the repository at this point in the history
Updates for v2
  • Loading branch information
bpostlethwaite committed Sep 28, 2017
2 parents 40d0100 + 48d23d9 commit 286c112
Show file tree
Hide file tree
Showing 36 changed files with 98 additions and 181 deletions.
115 changes: 21 additions & 94 deletions README.md
@@ -1,107 +1,34 @@
# Easy Javascript Colormaps
# colormap [![Build Status](https://travis-ci.org/bpostlethwaite/colormap.png)](https://travis-ci.org/bpostlethwaite/colormap)

[![Build Status](https://travis-ci.org/bpostlethwaite/colormap.png)](https://travis-ci.org/bpostlethwaite/colormap)
![all colormap output](./colormaps.png)

![all colormap output](./example/colormaps.png)
## Usage

## Simple example
[![npm install colormap](https://nodei.co/npm/colormap.png?mini=true)](https://npmjs.org/package/colormap/)

```javascript
var colormap = require('colormap')
options = {
colormap: 'jet', // pick a builtin colormap or pass your own
nshades: 72, // how many divisions
format: 'hex', // "hex" or "rgb" or "rgbaString"
alpha: 1 // set an alpha value or a linear alpha mapping [start, end]
}
cg = colormap(options)
```

where leaving `options = {}` or `undefined` results in the defaults given above. There is a minimum number of `nshades` divisions you can select since the algorithms for each colormap have different requirements. `colormap` throws an error if there are too few divisions for the chosen colormap and gives the minimum number required. You should be safe with `n > 10` for all the colormaps, though some require much less (much simpler to implemenent).
```js
let colormap = require('colormap')

## Options
The `colormap` option can be any of the supported builtin colormaps. Or you can add your own. For an example of how to add your own see the json format available at:

```javascript
colorscales = require('colormap/colorScales')
let colors = colormap({
colormap: 'jet'
nshades: 10,
format: 'hex',
alpha: 1
})
```

Colorscales are a sequence of objects containing an `index` and `rgb` key. The index defines how fast or slow the `rgb` values will change from one segment to the next. Ie.the steepness of the gradient between two segments. The `rgb` parameter can hold a length 3 or 4 array, depending if alpha values are included in the mapping.

## Return values
An array of hex values ('hex') or an array of length 4 arrays containing rgba values ('rgb') or an rgba css string ('rgbaString').

## Complete Example
This example will produce the colormap image used at top of this README. It uses all built in color maps and utilizes alpha channel mapping.

```javascript
var cmap = require('./..'),
canvas = document.getElementById('canvas'),
img = document.getElementById('background'),
c = canvas.getContext('2d'),
n = 48,
colormaps = [
'jet', 'hsv','hot','cool','spring','summer','autumn','winter','bone',
'copper','greys','YIGnBu','greens','YIOrRd','bluered','RdBu','picnic',
'rainbow','portland','blackbody','earth','electric'
];

img.onload = run;
## API

function drawColorMaps (colormap, name, height) {
/*
* Build up the color ranges and add text
*/
for (var j = 0; j < n; j++) {
c.fillStyle = colormap[j]; // start ind at index 0
c.fillRect(j*10, height, 10, 40);

}
c.fillStyle = '#262626';
c.font = '16px Helvetica';
c.fillText( name, n*10 + 10, height + 26);
}

function run() {
var height, colormap;
c.canvas.height = colormaps.length * 40 + img.height;
c.canvas.width = 648;

for (var i = 0; i < colormaps.length; i++) {
height = i*40;
colormap = cmap({
colormap: colormaps[i],
nshades: n,
format: 'rgbaString'
});
drawColorMaps(colormap, colormaps[i], height);
}

/*
* Now lets try some alpha maps overtop an image!
*/
var ilast = i;
c.drawImage(img, 0, i*40, 480, 240);

// remove background img
img.parentElement.removeChild(img);

for (var i = 0; i < colormaps.length; i++) {
height = (ilast + i)*40;
colormap = cmap({
colormap: colormaps[i],
nshades: n,
format: 'rgbaString',
alpha: [0, 1]
});
drawColorMaps(colormap, colormaps[i] + ' with transparency', height);
}
}
```
### list = colormap(options?)

Then just [browserify](https://github.com/substack/node-browserify) it and throw it in some html and it will output the image above!
Property | Default | Meaning
---|---|---
`colormap` | `'jet'` | Color map name from the image above or a custom color scale — a sequence of `{index, rgb}` objects, where index is `0..1` number and `rgb` is a length 3/4 array with values for the color stop.
`nshades` | `72` | Number of colors in returned array, the minimum number depends on `colormap`.
`format` | `'hex'` | `'hex'` for `#aabbcc`, `'rgbaString'` for `rgba(255, 255, 255, 1)`, `'rba'` for `[255, 255, 255, 1]`, `'float'` for `[1, 1, 1, 1]`.
`alpha` | `1` | Alpha range, can be an array with alpha values or just 2 values for start/end colors. |


## Credits

Color maps are inspired by [matplotlib](https://github.com/d3/d3-scale#sequential-color-scales) color scales, [cmocean](https://github.com/matplotlib/cmocean) oceanographic colormaps, [cosine gradients](https://github.com/thi-ng/color/blob/master/src/gradients.org) and others. Thanks to authors of these libs for their invaluable work.
Color maps are inspired by [matplotlib](https://github.com/d3/d3-scale#sequential-color-scales) color scales, [cmocean](https://github.com/matplotlib/cmocean) oceanographic colormaps, [cosine gradients](https://github.com/thi-ng/color/blob/master/src/gradients.org) and others. Thanks to authors of these libs for their invaluable work.
File renamed without changes.
Binary file added colormaps.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions example/example.js → example.js
@@ -1,6 +1,6 @@
var cmap = require('./..'),
canvas = document.getElementById('canvas'),
img = document.getElementById('background'),
var cmap = require('.'),
img = document.body.appendChild(document.createElement('img')),
canvas = document.body.appendChild(document.createElement('canvas')),
c = canvas.getContext('2d'),
n = 48,
colormaps = [
Expand All @@ -15,7 +15,9 @@ var cmap = require('./..'),
'cubehelix'
];

img.width = 480;
img.onload = run;
img.src = './night.jpg'

function drawColorMaps (colormap, name, height) {
/*
Expand All @@ -24,7 +26,6 @@ function drawColorMaps (colormap, name, height) {
for (var j = 0; j < n; j++) {
c.fillStyle = colormap[j]; // start ind at index 0
c.fillRect(j*10, height, 10, 40);

}
c.fillStyle = '#262626';
c.font = '16px Helvetica';
Expand Down
Binary file removed example/colormaps.png
Binary file not shown.
16 changes: 0 additions & 16 deletions example/example.html

This file was deleted.

82 changes: 47 additions & 35 deletions index.js
Expand Up @@ -5,9 +5,8 @@
*/
'use strict';

var at = require('arraytools');
var clone = require('clone');
var colorScale = require('./colorScales');
var colorScale = require('./colorScale');
var lerp = require('lerp')

module.exports = createColormap;

Expand All @@ -23,9 +22,9 @@ function createColormap (spec) {
b = [],
a = [];

if ( !at.isPlainObject(spec) ) spec = {};
if ( !spec ) spec = {};

nshades = spec.nshades || 72;
nshades = (spec.nshades || 72) - 1;
format = spec.format || 'hex';

colormap = spec.colormap;
Expand All @@ -38,10 +37,10 @@ function createColormap (spec) {
throw Error(colormap + ' not a supported colorscale');
}

cmap = clone(colorScale[colormap]);
cmap = colorScale[colormap];

} else if (Array.isArray(colormap)) {
cmap = clone(colormap);
cmap = colormap.slice();

} else {
throw Error('unsupported colormap option', colormap);
Expand All @@ -66,59 +65,72 @@ function createColormap (spec) {
alpha = [1, 1];

} else {
alpha = clone(spec.alpha);
alpha = spec.alpha.slice();
}

/*
* map index points from 0->1 to 0 -> n-1
*/
// map index points from 0..1 to 0..n-1
indicies = cmap.map(function(c) {
return Math.round(c.index * nshades);
});

/*
* Add alpha channel to the map
*/
if (alpha[0] < 0) alpha[0] = 0;
if (alpha[1] < 0) alpha[0] = 0;
if (alpha[0] > 1) alpha[0] = 1;
if (alpha[1] > 1) alpha[0] = 1;
// Add alpha channel to the map
alpha[0] = Math.min(Math.max(alpha[0], 0), 1);
alpha[1] = Math.min(Math.max(alpha[1], 0), 1);

var steps = cmap.map(function(c, i) {
var index = cmap[i].index

for (i = 0; i < indicies.length; ++i) {
index = cmap[i].index;
rgba = cmap[i].rgb;
var rgba = cmap[i].rgb.slice();

// if user supplies their own map use it
if (rgba.length === 4 && rgba[3] >= 0 && rgba[3] <= 1) continue;
if (rgba.length === 4 && rgba[3] >= 0 && rgba[3] <= 1) {
return rgba
}
rgba[3] = alpha[0] + (alpha[1] - alpha[0])*index;
}

return rgba
})


/*
* map increasing linear values between indicies to
* linear steps in colorvalues
*/
var colors = []
for (i = 0; i < indicies.length-1; ++i) {
nsteps = indicies[i+1] - indicies[i];
fromrgba = cmap[i].rgb;
torgba = cmap[i+1].rgb;
r = r.concat(at.linspace(fromrgba[0], torgba[0], nsteps ) );
g = g.concat(at.linspace(fromrgba[1], torgba[1], nsteps ) );
b = b.concat(at.linspace(fromrgba[2], torgba[2], nsteps ) );
a = a.concat(at.linspace(fromrgba[3], torgba[3], nsteps ) );
fromrgba = steps[i];
torgba = steps[i+1];

for (var j = 0; j < nsteps; j++) {
var amt = j / nsteps
colors.push([
Math.round(lerp(fromrgba[0], torgba[0], amt)),
Math.round(lerp(fromrgba[1], torgba[1], amt)),
Math.round(lerp(fromrgba[2], torgba[2], amt)),
lerp(fromrgba[3], torgba[3], amt)
])
}
}

r = r.map( Math.round );
g = g.map( Math.round );
b = b.map( Math.round );

colors = at.zip(r, g, b, a);
//add 1 step as last value
colors.push(cmap[cmap.length - 1].rgb.concat(alpha[1]))

if (format === 'hex') colors = colors.map( rgb2hex );
if (format === 'rgbaString') colors = colors.map( rgbaStr );
else if (format === 'rgbaString') colors = colors.map( rgbaStr );
else if (format === 'float') colors = colors.map( rgb2float );

return colors;
};

function rgb2float (rgba) {
return [
rgba[0] / 255,
rgba[1] / 255,
rgba[2] / 255,
rgba[3]
]
}

function rgb2hex (rgba) {
var dig, hex = '#';
Expand Down
File renamed without changes.
File renamed without changes
13 changes: 4 additions & 9 deletions package.json
@@ -1,23 +1,18 @@
{
"name": "colormap",
"version": "2.2.0",
"version": "2.3.0",
"description": "Great looking color maps",
"author": "bpostlethwaite",
"dependencies": {
"arraytools": "^1.1.2",
"clone": "^1.0.2"
"lerp": "^1.0.3"
},
"devDependencies": {
"color-space": "^1.14.3",
"tap": "^5.1"
"tape": "^4.7.0"
},
"files": [
"index.js",
"colorScales.js"
],
"main": "index.js",
"scripts": {
"test": "tap test/*.js",
"test": "node test.js",
"build": "browserify example/example.js -o example/bundle.js",
"draw": "budo test/draw.js"
},
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
23 changes: 21 additions & 2 deletions test/rgba-colorscale-test.js → test.js
@@ -1,5 +1,24 @@
var colormap = require('../.'),
test = require('tap').test;
var colormap = require('.'),
test = require('tape');


test('is object - object', function(t) {
t.plan(1);
var n = 15,
cg,
check = true;

// Display all the colormaps
var cms = ['jet', 'hsv' ,'hot', 'cool', 'spring', 'summer', 'autumn',
'winter', 'greys', 'bone', 'copper'];

for (var i = 0; i < cms.length; i++) {
cg = colormap({'colormap': cms[i], 'nshades': n });
check = check & (cg.length == n);
}

t.ok(check);
});

test('alpha config creates rgba arrays with correct alpha', function (t) {

Expand Down
21 changes: 0 additions & 21 deletions test/output-length-test.js

This file was deleted.

0 comments on commit 286c112

Please sign in to comment.