latest working updates to draft

This commit is contained in:
Walker Waylon Scott 2017-07-19 12:31:50 -05:00
parent bab7a654ff
commit 84f6cca0e4
144 changed files with 19664 additions and 56 deletions

View file

@ -11,3 +11,5 @@ todays_outfit = ['#EC1616', '#F0DC9D', '#006CF8', '#000000', '#EC1616', '#F0DC9D
# http://www.colourlovers.com/palette/2097539/Sea_Urchin_Spines # http://www.colourlovers.com/palette/2097539/Sea_Urchin_Spines
sea_urchin_spines = ['#000E29', '#0071A7', '#24A854', '#057976', '#004444', '#000E29', '#0071A7', '#24A854'] sea_urchin_spines = ['#000E29', '#0071A7', '#24A854', '#057976', '#004444', '#000E29', '#0071A7', '#24A854']
# https://color.adobe.com/index.cfm#themeID/937271 # https://color.adobe.com/index.cfm#themeID/937271
canva = ['#F15847', '#0C243B', '#C7E0E4', '#6FA2B6', '#42637C']

View file

@ -153,7 +153,7 @@ class top_movies(Resource):
data = filter_with_args(args) data = filter_with_args(args)
df = (data.movie df = (data.movie
.sort_values('imdb_score', ascending=False) .sort_values('gross', ascending=False)
.drop_duplicates(subset=['movie_title']) .drop_duplicates(subset=['movie_title'])
.set_index('movie_title') .set_index('movie_title')
[['title_year', 'imdb_score', 'gross']] [['title_year', 'imdb_score', 'gross']]
@ -184,15 +184,9 @@ class score_timeseries(Resource):
df['DATE'] = df.index df['DATE'] = df.index
df['DATE'] = df['DATE'].astype('str').fillna('1900-01-01') df['DATE'] = df['DATE'].astype('str').fillna('1900-01-01')
print(df.head()) print(df.head())
score_timeseries = {'columns':[['IMDB Score'] + df['IMDB Score'].values.tolist(), score_timeseries = {'columns':[['IMDB Score (right)'] + df['IMDB Score'].values.tolist(),
['gross'] + df['gross'].values.tolist(), ['gross'] + df['gross'].values.tolist(),
['x'] + df.DATE.astype(str).values.tolist()], ['x'] + df.DATE.astype(str).values.tolist()],}
# ['x'] + df.index.values.tolist()],
'colors':{
'IMDB Score': '#0071A7',
'gross': '#4D9913',
'x': '#08414C'
}}
return jsonify(score_timeseries) return jsonify(score_timeseries)
@api.route('/download') @api.route('/download')
@ -213,8 +207,6 @@ class sentiment(Resource):
keywords = TextBlob(' '.join(data.keyword.plot_keywords.values)) keywords = TextBlob(' '.join(data.keyword.plot_keywords.values))
results = {'columns':[['polarity'] + [round(keywords.sentiment.polarity + .1, 3) * 250], results = {'columns':[['polarity'] + [round(keywords.sentiment.polarity + .1, 3) * 250],
['subjectivity'] + [round(keywords.sentiment.subjectivity + .1, 3) * 150]], ['subjectivity'] + [round(keywords.sentiment.subjectivity + .1, 3) * 150]],
'colors':{'polarity':'grey',
'subjectivity':'#afafaf'}
} }
return jsonify(results) return jsonify(results)

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
src/static/bk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
src/static/bottom.pdn Normal file

Binary file not shown.

BIN
src/static/bottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View file

@ -1,9 +1,69 @@
html{
--score-color:#0071A7;
--gross-color:#4D9913;
--dark-blue:#0C243B;
--light-blue:#384c65;
--score-color:#0C243B;
--axis-color: var(--score-color);
}
body{ body{
font-family:Tahoma, Geneva, sans-serif; font-family:Tahoma, Geneva, sans-serif;
background-color:white; color:#C7E0E4;
background-color:#0C243B;
} }
#top-image{
background-image: url("/static/top.png");
background-repeat: repeat;
}
#bottom-image{
background-image: url("/static/bottom.png");
background-repeat: repeat;
}
/*@keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
@-webkit-keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}*/
/*#timeseries-chart {
stroke: #fff !important;
}*/
.c3 .c3-axis-x path, .c3 .c3-axis-x line,
.c3 .c3-axis-y path, .c3 .c3-axis-y line,
.c3 .c3-axis-y2 path, .c3 .c3-axis-y2 line {
stroke: var(--axis-color);
}
.c3 .c3-axis-x g,
.c3 .c3-axis-y g,
.c3 .c3-axis-y2 g,
.c3 .c3-legend-item-data text {
color: var(--axis-color);
fill: var(--axis-color);
}
.container {
color: #C7E0E4;
box-shadow: 0px 30px 40px rgba(0,0,0,1);
})
.kpi { .kpi {
/* color: #B80000; */ /* color: #B80000; */
padding:5px 5px 5px 5px ;
font-weight:4; font-weight:4;
font-size:16px; font-size:16px;
} }
@ -11,7 +71,18 @@ body{
/* color: #B80000; */ /* color: #B80000; */
font-weight:8; font-weight:8;
font-size:18px; font-size:18px;
padding: 10px 20px 10px 0px; /*padding: 10px 20px 10px 0px;*/
height:25px;
/* height: 75px; */
}
#score{
color: var(--score-color);
color: var(--light-blue);
}
#gross{
color: var(--gross-color);
} }
.chosen{ .chosen{
@ -54,12 +125,17 @@ body{
.title{ .title{
font-size:22px; font-size:22px;
color:#0071A7; color:var(--dark-blue);
font: bold; font: bold;
} }
.note{
color:var(--dark-blue);
}
.sentiment-chart-title{ .sentiment-chart-title{
color:#0071A7; color:var(--dark-blue);
/*text-align: center;*/ /*text-align: center;*/
} }
.word-cloud-title{ .word-cloud-title{

View file

@ -3,6 +3,13 @@ var mil = d3.format('$.3s')
var update_freq = 200 var update_freq = 200
// $(document).ready(function() {
var style = getComputedStyle(document.body);
score_color = style.getPropertyValue('--score-color');
gross_color = style.getPropertyValue('--gross-color');
// }
var data = { var data = {
'size': { 'size': {
'height': 300 'height': 300
@ -10,7 +17,7 @@ var data = {
'data': { 'data': {
'x': 'x', 'x': 'x',
'axes': { 'axes': {
'IMDB Score': 'y2', 'IMDB Score (right)': 'y2',
'gross': 'y', 'gross': 'y',
'x': 'y' 'x': 'y'
}, },
@ -26,8 +33,8 @@ var data = {
] ]
], ],
'colors': { 'colors': {
'IMDB Score': '#B80000', 'IMDB Score (right)': score_color,
'gross': '#0071A7', 'gross': gross_color,
'x': '#08414C' 'x': '#08414C'
} }
}, },
@ -97,8 +104,8 @@ var sentiment_data = {
bindto:'#sentiment-chart', bindto:'#sentiment-chart',
data: { data: {
colors: { colors: {
polarity: "grey", polarity: chroma(score_color).darken().hex(),
subjectivity: "#afafaf"}, subjectivity: score_color, },
columns: [ columns: [
['polarity', 10], ['polarity', 10],
['subjectivity', 10], ['subjectivity', 10],
@ -108,7 +115,7 @@ var sentiment_data = {
}, },
bar: { bar: {
width: { width: {
ratio: .7 // this makes bar width 50% of length between ticks ratio: 100 // this makes bar width 50% of length between ticks
}, },
// or // or
// width: 100 // this makes bar width 100px // width: 100 // this makes bar width 100px
@ -119,8 +126,11 @@ var sentiment_data = {
}, },
tooltip:{show:false}, tooltip:{show:false},
grid: {y: {lines: [{value:10, text:'neutral'}, grid: {y: {lines: [{value:10, text:'neutral'},
{value:100, text:'max'}, {value:100, text:'positive'},
{value:0, text:'min'}]}} {value:100, text:' subjective', position:'start'},
{value:0, text:'negative'},
{value:0, text:' objective', position:'start'},
]}}
} }
@ -138,7 +148,12 @@ word_coud_settings = {
width: wc_width, width: wc_width,
height: wc_height, height: wc_height,
classPattern: null, classPattern: null,
colors: ['#0071A7', '#000E29', '#24A854',],// '#ffeda0', '#ffffcc'], colors: [score_color,
// gross_color,
chroma(score_color).darken().hex(),
// chroma(gross_color).darken().hex(),
chroma(score_color).darken().darken().hex(),
],// '#ffeda0', '#ffffcc'],
fontSize: { fontSize: {
from: 0.1, from: 0.1,
to: 0.02 to: 0.02
@ -246,17 +261,6 @@ function update_words()
}) })
} }
poster_img = '';
function poster(title){
console.log(title)
var info = $.get('http://www.omdbapi.com/?t=' + title + '&apikey=90424a9e')
return info.done( function(){
poster_img = '<img src=' + info.responseJSON['Poster'] + '>'
console.log(poster_img)
return poster_img
}
)
}
function update_top_movies(start_year, end_year) function update_top_movies(start_year, end_year)
{ {
@ -278,8 +282,7 @@ function update_top_movies(start_year, end_year)
window.promises = promises window.promises = promises
for (i in promises){ for (i in promises){
console.log() console.log()
h = promises[i].responseJSON['Title'] + '<br> <img src=' + promises[i].responseJSON['Poster'] + '><br><br>' $('#poster-' + i).html('<img src=' + promises[i].responseJSON['Poster'] + ' width=75%>')
$('#poster-' + i).html('<img src=' + promises[i].responseJSON['Poster'] + '>')
$('#title-' + i).html(promises[i].responseJSON['Title']) $('#title-' + i).html(promises[i].responseJSON['Title'])
} }
@ -329,3 +332,29 @@ function update_sentiment_year(year)
} }
$(document).ready(function() {
var movementStrength = 30;
var top_height = movementStrength / $(window).height();
var top_width = movementStrength / $(window).width();
$("#top-image").mousemove(function(e){
var pageX = e.pageX - ($(window).width() / 2);
var pageY = e.pageY - ($(window).height() / 2);
var newvalueX = top_width * pageX * -1 - 25;
var newvalueY = top_height * pageY * -1 - 50;
$('#top-image').css("background-position", newvalueX+"px "+newvalueY+"px");
});
var movementStrength = 10;
var height = movementStrength / $(window).height();
var width = movementStrength / $(window).width();
$("#bottom-image").mousemove(function(e){
var pageX = e.pageX - ($(window).width() / 2);
var pageY = e.pageY - ($(window).height() / 2);
var newvalueX = width * pageX * -1 - 25;
var newvalueY = height * pageY * -1 - 50;
$('#bottom-image').css("background-position", newvalueX+"px "+newvalueY+"px");
});
});

10
src/static/node_modules/chroma-js/.npmignore generated vendored Normal file
View file

@ -0,0 +1,10 @@
readme (Autosaved).md
m.txt
.DS_Store
license.coffee
node_modules
yarn.lock

6
src/static/node_modules/chroma-js/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,6 @@
language: node_js
node_js:
- 0.12
- 0.11
before_script: "npm install -g grunt-cli"
script: "npm run-script build && npm run-script test"

45
src/static/node_modules/chroma-js/CHANGELOG.md generated vendored Normal file
View file

@ -0,0 +1,45 @@
# 1.3.3
* added [color.clipped](https://gka.github.io/chroma.js/#color-clipped)
* added [chroma.distance](https://gka.github.io/chroma.js/#chroma-distance)
* added [chroma.deltaE](https://gka.github.io/chroma.js/#chroma-deltae)
* [color.set](https://gka.github.io/chroma.js/#color-set) now returns a new chroma instance
* chroma.scale now allows [disabling of internal cache](https://gka.github.io/chroma.js/#scale-cache)
* [chroma.average](https://gka.github.io/chroma.js/#chroma-average) now works with any color mode
* added unit tests for color conversions
* use hex colors as default string representation
* RGB channels are now stored as floats internally for higher precision
* bugfix with cubehelix and constant lightness
* bugfix in chroma.limits quantiles
* bugfix when running scale.colors(1)
* bugfix in hsi2rgb color conversion
# 1.2.2
* scale.colors() now returns the original colors instead of just min/max range
# 1.2.0
* added chroma.average for averaging colors
# 1.1.0
* refactored chroma.scale
* changed behaviour of scale.domain
* added scale.classes
* added scale.padding
# 1.0.2
* standardized alpha channel construction
* chroma.bezier automatically returns chroma.scale
# 1.0.1
* added simple color output to chroma.scale().colors()
# 1.0.0
* numeric interpolation does what it should
* refactored and modularized code base
* changed argument order of Color::interpolate

84
src/static/node_modules/chroma-js/Gruntfile.js generated vendored Normal file
View file

@ -0,0 +1,84 @@
"use strict";
var fs = require('fs'),
pkgInfo = JSON.parse(fs.readFileSync(__dirname + '/package.json'));
module.exports = function(grunt) {
grunt.initConfig({
clean: {
pre: [
'chroma.js',
'chroma.min.js',
'license.coffee',
],
post: ['chroma.coffee']
},
coffee: {
compile: {
options: {
join: true
},
files: {
'chroma.js': [
'license.coffee',
'chroma.coffee'
],
},
}
},
replace: {
dist: {
options: { patterns: [{ match: 'version', replacement: pkgInfo.version }] },
files: [{expand: true, flatten: true, src: ['chroma.js'], dest: '.'}]
}
},
uglify: {
options: {
banner: "/*\n" + fs.readFileSync("LICENSE", {encoding: "utf8"}) + "\n*/\n",
},
my_target: {
files: {
'chroma.min.js': ['chroma.js']
},
},
},
copy: {
main: {
files: [
// copy build files into docs folder
{expand: true, src: ['chroma*.js'], dest: 'docs/libs/', filter: 'isFile'},
],
},
},
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-replace');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('license', function() {
var license = [
"###*",
" * @license",
" *",
].concat(fs.readFileSync('LICENSE', {encoding: "utf8"}).split("\n").map(function(line) {
return " * " + line;
}));
license.push("###\n");
fs.writeFileSync('license.coffee', license.join("\n"));
});
grunt.registerTask('catty', function() {
require("catty")({ global: true })
.coffee(true)
.addLibrary("src")
.cat("src/index.coffee", "./chroma.coffee");
});
grunt.registerTask('default', ['clean:pre', 'license', 'catty', 'coffee', 'replace',
'uglify', 'copy', 'clean:post']);
};

28
src/static/node_modules/chroma-js/LICENSE generated vendored Normal file
View file

@ -0,0 +1,28 @@
chroma.js - JavaScript library for color conversions
Copyright (c) 2011-2017, Gregor Aisch
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name Gregor Aisch may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
src/static/node_modules/chroma-js/LICENSE-colors generated vendored Normal file
View file

@ -0,0 +1,22 @@
chroma.js includes colors from colorbrewer2.org,
which are released under the following license:
Copyright (c) 2002 Cynthia Brewer, Mark Harrower,
and The Pennsylvania State University.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied. See the License for the specific
language governing permissions and limitations under the License.
Named colors are taken from X11 Color Names.
http://www.w3.org/TR/css3-color/#svg-color

34
src/static/node_modules/chroma-js/bower.json generated vendored Normal file
View file

@ -0,0 +1,34 @@
{
"name": "chroma-js",
"description": "JavaScript library for color conversions",
"main": [
"./chroma.js"
],
"ignore": [
"doc",
"src",
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"homepage": "https://github.com/gka/chroma.js",
"authors": [
"Gregor Aisch <contact@vis4.net>"
],
"keywords": [
"color",
"scale",
"gradient",
"scheme",
"rgb",
"hsv",
"hsl",
"css",
"lch",
"lab",
"hcg"
],
"license": "MIT"
}

2707
src/static/node_modules/chroma-js/chroma.js generated vendored Normal file

File diff suppressed because it is too large Load diff

33
src/static/node_modules/chroma-js/chroma.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

7
src/static/node_modules/chroma-js/docs/Makefile generated vendored Normal file
View file

@ -0,0 +1,7 @@
all:
node $$(which markdown) -f gfm -s src/index.css src/index.md --title "chroma.js api docs!" > index.html
bin/post-process
preview:
http-server
# python -m SimpleHTTPServer

BIN
src/static/node_modules/chroma-js/docs/assets/bg.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

View file

@ -0,0 +1,11 @@
#!/usr/bin/env node
var fs = require('fs');
var index = fs.readFileSync('index.html', 'utf-8'),
footer = fs.readFileSync('src/footer.inc.html', 'utf-8');
index = index.replace('</body>', '\n'+footer+'\n</body>');
index = index.replace('<body>', '<body><div class="wrap">');
index = index.replace('</body>', '</div></body>');
fs.writeFileSync('index.html', index);

685
src/static/node_modules/chroma-js/docs/index.html generated vendored Normal file
View file

@ -0,0 +1,685 @@
<!DOCTYPE html>
<html>
<head>
<title>chroma.js api docs!</title>
<link rel="stylesheet" href="src/index.css">
</head>
<body><div class="wrap">
<h1 id="chroma-js">chroma.js</h1>
<p><strong>chroma.js</strong> is a tiny JavaScript library (14kB) for dealing with colors!</p>
<p><a href="https://travis-ci.org/gka/chroma.js"><img src="https://travis-ci.org/gka/chroma.js.svg?branch=master" alt="Build Status"></a></p>
<h2 id="quick-start">Quick-start</h2>
<p>Here are a couple of things chroma.js can do for you:</p>
<ul>
<li>read colors from a wide range of formats</li>
<li>analyze and manipulate colors</li>
<li>convert colors into wide range of formats</li>
<li>linear and bezier interpolation in different color spaces</li>
</ul>
<p>Here&#39;s an example for a simple read / manipulate / output chain:</p>
<pre><code class="lang-js">chroma(&#39;pink&#39;).darken().saturate(2).hex()
</code></pre>
<p>Aside from that, chroma.js can also help you <strong>generate nice colors</strong> using various methods, for instance to be <a href="https://www.vis4.net/blog/posts/avoid-equidistant-hsv-colors/">used</a> in color palette for maps or data visualization.</p>
<pre><code class="lang-js">chroma.scale([&#39;#fafa6e&#39;,&#39;#2A4858&#39;])
.mode(&#39;lch&#39;).colors(6)
</code></pre>
<p>chroma.js has a lot more to offer, but that&#39;s the gist of it.</p>
<h2 id="api">API</h2>
<h3 id="chroma">chroma</h3>
<h4 id="-color-">(<em>color</em>)</h4>
<p>The first step is to get your color into chroma.js. That&#39;s what the generic constructor <code>chroma()</code> does. The function is trying to guess the color format for you. For instances, it will recognized any named color from the W3CX11 specification: </p>
<pre><code class="lang-js">chroma(&#39;hotpink&#39;)
</code></pre>
<p>If there&#39;s no matching named color chroma.js checks for a <strong>hexadecimal string</strong>. It ignores case, the <code>#</code> sign is optional, and the shorter three letter format is recognized as well. So any of these are valid hexadecimal representations: <code>#ff3399</code>, <code>FF3399</code>, <code>#f39</code>, etc.</p>
<pre><code class="lang-js">chroma(&#39;#ff3399&#39;);
chroma(&#39;F39&#39;);
</code></pre>
<p>In addition to hex strings, <strong>hexadecimal numbers</strong> (in fact, just any number between <code>0</code> and <code>16777215</code>), will be recognized, too.</p>
<pre><code class="lang-js">chroma(0xff3399)
</code></pre>
<p>If you pass the RGB channels individually, too. Each parameter must be within <code>0..255</code>. You can pass the numbers as individual arguments or as array.</p>
<pre><code class="lang-js">chroma(0xff, 0x33, 0x99);
chroma(255, 51, 153);
chroma([255, 51, 153]);
</code></pre>
<p>You can construct colors from different color spaces by passing the name of color space as the last argument. Here we define the same color in HSL by passing the h<em>ue angle (0-360) and percentages for </em>s<em>aturation and </em>l*ightness:</p>
<pre><code class="lang-js">chroma(330, 1, 0.6, &#39;hsl&#39;)
</code></pre>
<h3 id="chroma-hsl">chroma.hsl</h3>
<h4 id="-hue-saturation-lightness-">(hue, saturation, lightness)</h4>
<p>Alternatively, every color space has its own constructor function under the <code>chroma</code> namespace. For a list of all supported color spaces, check the <a href="#supported-color-spaces-and-output-formats">appendix</a>.</p>
<pre><code class="lang-js">chroma.hsl(330, 1, 0.6)
</code></pre>
<h3 id="chroma-hsv">chroma.hsv</h3>
<h4 id="-hue-saturation-value-">(hue, saturation, value)</h4>
<h3 id="chroma-lab">chroma.lab</h3>
<h4 id="-lightness-a-b-">(Lightness, a, b)</h4>
<h3 id="chroma-lch">chroma.lch</h3>
<h4 id="-lightness-chroma-hue-">(Lightness, chroma, hue)</h4>
<p>The range for <code>lightness</code> and <code>chroma</code> depend on the hue, but go roughly from 0..100-150. The range for <code>hue</code> is 0..360.</p>
<pre><code class="lang-js">chroma.lch(80, 40, 130);
chroma(80, 40, 130, &#39;lch&#39;);
</code></pre>
<h3 id="chroma-hcl">chroma.hcl</h3>
<h4 id="-hue-chroma-lightness-">(hue, chroma, lightness)</h4>
<p>You can use <strong>hcl</strong> instead of Lch. Lightness and hue channels are switched to be more consistent with HSL.</p>
<pre><code class="lang-js">chroma.hcl(130, 40, 80);
chroma(130, 40, 80, &#39;hcl&#39;);
</code></pre>
<h3 id="chroma-cmyk">chroma.cmyk</h3>
<h4 id="-cyan-magenta-yellow-black-">(cyan, magenta, yellow, black)</h4>
<p>Each between 0 and 1.</p>
<pre><code class="lang-js">chroma.cmyk(0.2, 0.8, 0, 0);
chroma(0.2, 0.8, 0, 0, &#39;cmyk&#39;);
</code></pre>
<h3 id="chroma-gl">chroma.gl</h3>
<h4 id="-red-green-blue-alpha-">(red, green, blue, [alpha])</h4>
<p><strong>GL</strong> is a variant of RGB(A), with the only difference that the components are normalized to the range of <code>0..1</code>.</p>
<pre><code class="lang-js">chroma.gl(0.6, 0, 0.8);
chroma.gl(0.6, 0, 0.8, 0.5);
chroma(0.6, 0, 0.8, &#39;gl&#39;);
</code></pre>
<h3 id="chroma-temperature">chroma.temperature</h3>
<h4 id="-k-">(K)</h4>
<p>Returns a color from the <a href="http://www.zombieprototypes.com/?p=210">color temperature</a> scale. Based on <a href="https://github.com/neilbartlett/color-temperature">Neil Bartlett&#39;s implementation</a>. </p>
<pre><code class="lang-js">chroma.temperature(2000); // candle light
chroma.temperature(3500); // sunset
chroma.temperature(6500); // daylight
</code></pre>
<p>The effective temperature range goes from <code>0</code> to about <code>30000</code> Kelvin,</p>
<pre><code class="lang-js">f = function(i) {
return chroma.temperature(i * 30000)
}
</code></pre>
<h3 id="chroma-mix">chroma.mix</h3>
<h4 id="-color1-color2-ratio-0-5-mode-rgb-">(color1, color2, ratio=0.5, mode=&#39;rgb&#39;)</h4>
<p>Mixes two colors. The mix <em>ratio</em> is a value between 0 and 1.</p>
<pre><code class="lang-js">chroma.mix(&#39;red&#39;, &#39;blue&#39;);
chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.25);
chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.75);
</code></pre>
<p>The color mixing produces different results based the color space used for interpolation.</p>
<pre><code class="lang-js">chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.5, &#39;rgb&#39;);
chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.5, &#39;hsl&#39;);
chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.5, &#39;lab&#39;);
chroma.mix(&#39;red&#39;, &#39;blue&#39;, 0.5, &#39;lch&#39;);
</code></pre>
<h3 id="chroma-average">chroma.average</h3>
<h4 id="-colors-mode-rgb-">(colors, mode=&#39;rgb&#39;)</h4>
<p>Similar to <code>chroma.mix</code>, but accepts more than two colors. Simple averaging of R,G,B components and the alpha channel.</p>
<pre><code class="lang-js">colors = [&#39;#ddd&#39;, &#39;yellow&#39;, &#39;red&#39;, &#39;teal&#39;];
chroma.average(colors);
chroma.average(colors, &#39;lab&#39;);
chroma.average(colors, &#39;lch&#39;);
</code></pre>
<p>Also works with alpha channels.</p>
<pre><code class="lang-js">chroma.average([&#39;red&#39;, &#39;rgba(0,0,0,0.5)&#39;]).css();
</code></pre>
<h3 id="chroma-blend">chroma.blend</h3>
<h4 id="-color1-color2-mode-">(color1, color2, mode)</h4>
<p>Blends two colors using RGB channel-wise blend functions. Valid blend modes are <code>multiply</code>, <code>darken</code>, <code>lighten</code>, <code>screen</code>, <code>overlay</code>, <code>burn</code>, and <code>dogde</code>.</p>
<pre><code class="lang-js">chroma.blend(&#39;4CBBFC&#39;, &#39;EEEE22&#39;, &#39;multiply&#39;);
chroma.blend(&#39;4CBBFC&#39;, &#39;EEEE22&#39;, &#39;darken&#39;);
chroma.blend(&#39;4CBBFC&#39;, &#39;EEEE22&#39;, &#39;lighten&#39;);
</code></pre>
<h3 id="chroma-random">chroma.random</h3>
<h4 id="-">()</h4>
<p>Returns a random color.</p>
<pre><code class="lang-js">chroma.random();
chroma.random();
chroma.random();
</code></pre>
<h3 id="chroma-contrast">chroma.contrast</h3>
<h4 id="-color1-color2-">(color1, color2)</h4>
<p>Computes the WCAG contrast ratio between two colors. A minimum contrast of 4.5:1 <a href="http://www.w3.org/TR/WCAG20-TECHS/G18.html">is recommended</a> to ensure that text is still readable against a background color.</p>
<pre><code class="lang-js">// contrast smaller than 4.5 = too low
chroma.contrast(&#39;pink&#39;, &#39;hotpink&#39;);
// contrast greater than 4.5 = high enough
chroma.contrast(&#39;pink&#39;, &#39;purple&#39;);
</code></pre>
<h3 id="chroma-distance">chroma.distance</h3>
<h4 id="-color1-color2-mode-lab-">(color1, color2, mode=&#39;lab&#39;)</h4>
<p>Computes the <a href="https://en.wikipedia.org/wiki/Euclidean_distance#Three_dimensions">eucledian distance</a> between two colors in a given color space (default is <code>Lab</code>). </p>
<pre><code class="lang-js">chroma.distance(&#39;#fff&#39;, &#39;#ff0&#39;, &#39;rgb&#39;);
chroma.distance(&#39;#fff&#39;, &#39;#f0f&#39;, &#39;rgb&#39;);
chroma.distance(&#39;#fff&#39;, &#39;#ff0&#39;);
chroma.distance(&#39;#fff&#39;, &#39;#f0f&#39;);
</code></pre>
<h3 id="chroma-deltae">chroma.deltaE</h3>
<h4 id="-reference-sample-l-1-c-1-">(reference, sample, L=1, C=1)</h4>
<p>Computes <a href="https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_.281984.29">color difference</a> as developed by the Colour Measurement Committee of the Society of Dyers and Colourists (CMC) in 1984. The implementation is adapted from <a href="https://web.archive.org/web/20160306044036/http://www.brucelindbloom.com/javascript/ColorDiff.js">Bruce Lindbloom</a>. The parameters L and C are weighting factors for lightness and chromacity.</p>
<pre><code class="lang-js">chroma.deltaE(&#39;#ededee&#39;, &#39;#edeeed&#39;);
chroma.deltaE(&#39;#ececee&#39;, &#39;#eceeec&#39;);
chroma.deltaE(&#39;#e9e9ee&#39;, &#39;#e9eee9&#39;);
chroma.deltaE(&#39;#e4e4ee&#39;, &#39;#e4eee4&#39;);
chroma.deltaE(&#39;#e0e0ee&#39;, &#39;#e0eee0&#39;);
</code></pre>
<h3 id="chroma-brewer">chroma.brewer</h3>
<p>chroma.brewer is an map of ColorBrewer scales that are included in chroma.js for convenience. chroma.scale uses the colors to construct.</p>
<pre><code class="lang-js">chroma.brewer.OrRd
</code></pre>
<h3 id="chroma-limits">chroma.limits</h3>
<h4 id="-data-mode-n-">(data, mode, n)</h4>
<p>A helper function that computes class breaks for you, based on data. It supports the modes <em>equidistant</em> (e), <em>quantile</em> (q), <em>logarithmic</em> (l), and <em>k-means</em> (k). Let&#39;s take a few numbers as sample data. </p>
<pre><code class="lang-js">var data = [2.0,3.5,3.6,3.8,3.8,4.1,4.3,4.4,
4.6,4.9,5.2,5.3,5.4,5.7,5.8,5.9,
6.2,6.5,6.8,7.2,8];
</code></pre>
<p><strong>equidistant</strong> breaks are computed by dividing the total range of the data into <em>n</em> groups of equal size.</p>
<pre><code class="lang-js">chroma.limits(data, &#39;e&#39;, 4);
</code></pre>
<p>In the <strong>quantile</strong> mode, the input domain is divided by quantile ranges. </p>
<pre><code class="lang-js">chroma.limits(data, &#39;q&#39;, 4);
</code></pre>
<p><strong>logarithmic</strong> breaks are equidistant breaks but on a logarithmic scale. </p>
<pre><code class="lang-js">chroma.limits(data, &#39;l&#39;, 4);
</code></pre>
<p><strong>k-means</strong> break is using the 1-dimensional <a href="https://en.wikipedia.org/wiki/K-means_clustering">k-means clustering</a> algorithm to find (roughly) <em>n</em> groups of &quot;similar&quot; values. Note that this k-means implementation does not guarantee to find exactly <em>n</em> groups.</p>
<pre><code class="lang-js">chroma.limits(data, &#39;k&#39;, 4);
</code></pre>
<h2 id="color">color</h2>
<h3 id="color-alpha">color.alpha</h3>
<h4 id="-a-">(a)</h4>
<p>Get and set the color opacity using <code>color.alpha</code>.</p>
<pre><code class="lang-js">chroma(&#39;red&#39;).alpha(0.5);
chroma(&#39;rgba(255,0,0,0.35)&#39;).alpha();
</code></pre>
<h3 id="color-darken">color.darken</h3>
<h4 id="-value-1-">(value=1)</h4>
<p>Once loaded, chroma.js can change colors. One way we already saw above, you can change the lightness. </p>
<pre><code class="lang-js">chroma(&#39;hotpink&#39;).darken();
chroma(&#39;hotpink&#39;).darken(2);
chroma(&#39;hotpink&#39;).darken(2.6);
</code></pre>
<h3 id="color-brighten">color.brighten</h3>
<h4 id="-value-1-">(value=1)</h4>
<p>Similar to <code>darken</code>, but the opposite direction</p>
<pre><code class="lang-js">chroma(&#39;hotpink&#39;).brighten();
chroma(&#39;hotpink&#39;).brighten(2);
chroma(&#39;hotpink&#39;).brighten(3);
</code></pre>
<h3 id="color-saturate">color.saturate</h3>
<h4 id="-value-1-">(value=1)</h4>
<p>Changes the saturation of a color by manipulating the Lch chromacity.</p>
<pre><code class="lang-js">chroma(&#39;slategray&#39;).saturate();
chroma(&#39;slategray&#39;).saturate(2);
chroma(&#39;slategray&#39;).saturate(3);
</code></pre>
<h3 id="color-desaturate">color.desaturate</h3>
<h4 id="-value-1-">(value=1)</h4>
<p>Similar to <code>saturate</code>, but the opposite direction.</p>
<pre><code class="lang-js">chroma(&#39;hotpink&#39;).desaturate();
chroma(&#39;hotpink&#39;).desaturate(2);
chroma(&#39;hotpink&#39;).desaturate(3);
</code></pre>
<h3 id="color-set">color.set</h3>
<h4 id="-channel-value-">(channel, value)</h4>
<p>Changes a single channel and returns the result a new <code>chroma</code> object.</p>
<pre><code class="lang-js">// change hue to 0 deg (=red)
chroma(&#39;skyblue&#39;).set(&#39;hsl.h&#39;, 0);
// set chromacity to 30
chroma(&#39;hotpink&#39;).set(&#39;lch.c&#39;, 30);
</code></pre>
<p>Relative changes work, too:</p>
<pre><code class="lang-js">// half Lab lightness
chroma(&#39;orangered&#39;).set(&#39;lab.l&#39;, &#39;*0.5&#39;);
// double Lch saturation
chroma(&#39;darkseagreen&#39;).set(&#39;lch.c&#39;, &#39;*2&#39;);
</code></pre>
<h3 id="color-get">color.get</h3>
<h4 id="-channel-">(channel)</h4>
<p>Returns a single channel value.</p>
<pre><code class="lang-js">chroma(&#39;orangered&#39;).get(&#39;lab.l&#39;);
chroma(&#39;orangered&#39;).get(&#39;hsl.l&#39;);
chroma(&#39;orangered&#39;).get(&#39;rgb.g&#39;);
</code></pre>
<h3 id="color-luminance">color.luminance</h3>
<h4 id="-lum-mode-rgb-">([lum, mode=&#39;rgb&#39;])</h4>
<p>If called without arguments color.luminance returns the relative brightness, according to the <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef">WCAG definition</a>. Normalized to <code>0</code> for darkest black and <code>1</code> for lightest white.</p>
<pre><code class="lang-js">chroma(&#39;white&#39;).luminance();
chroma(&#39;aquamarine&#39;).luminance();
chroma(&#39;hotpink&#39;).luminance();
chroma(&#39;darkslateblue&#39;).luminance();
chroma(&#39;black&#39;).luminance();
</code></pre>
<p>chroma.js also allows you to <strong>adjust the luminance</strong> of a color. The source color will be interpolated with black or white until the correct luminance is found.</p>
<pre><code class="lang-js">// set lumincance to 50% for all colors
chroma(&#39;white&#39;).luminance(0.5);
chroma(&#39;aquamarine&#39;).luminance(0.5);
chroma(&#39;hotpink&#39;).luminance(0.5);
chroma(&#39;darkslateblue&#39;).luminance(0.5);
</code></pre>
<p>By default, this interpolation is done in RGB, but you can interpolate in different color spaces by passing them as second argument:</p>
<pre><code class="lang-js">chroma(&#39;aquamarine&#39;).luminance(0.5); // rgb
chroma(&#39;aquamarine&#39;).luminance(0.5, &#39;lab&#39;);
chroma(&#39;aquamarine&#39;).luminance(0.5, &#39;hsl&#39;);
</code></pre>
<h3 id="color-hex">color.hex</h3>
<p>Finally, chroma.js allows you to output colors in various color spaces and formats.</p>
<p>Most often you will want to output the color as hexadecimal string.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).hex()
</code></pre>
<h3 id="color-name">color.name</h3>
<p>Returns the named color. Falls back to hexadecimal RGB string, if the color isn&#39;t present.</p>
<pre><code class="lang-js">chroma(&#39;#ffa500&#39;).name();
chroma(&#39;#ffa505&#39;).name();
</code></pre>
<h3 id="color-css">color.css</h3>
<p>Returns a <code>RGB()</code> or <code>HSL()</code> string representation that can be used as CSS-color definition.</p>
<pre><code class="lang-js">chroma(&#39;teal&#39;).css();
chroma(&#39;teal&#39;).alpha(0.5).css();
chroma(&#39;teal&#39;).css(&#39;hsl&#39;);
</code></pre>
<h3 id="color-rgb">color.rgb</h3>
<h4 id="-round-true-">(round=true)</h4>
<p>Returns an array with the <code>red</code>, <code>green</code>, and <code>blue</code> component, each as number within the range <code>0..255</code>. Chroma internally stores RGB channels as floats but rounds the numbers before returning them. You can pass <code>false</code> to prevent the rounding.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).rgb();
chroma(&#39;orange&#39;).darken().rgb();
chroma(&#39;orange&#39;).darken().rgb(false);
</code></pre>
<h3 id="color-rgba">color.rgba</h3>
<h4 id="-round-true-">(round=true)</h4>
<p>Just like <code>color.rgb</code> but adds the alpha channel to the returned array.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).rgba();
chroma(&#39;hsla(20, 100%, 40%, 0.5)&#39;).rgba();
</code></pre>
<h3 id="color-hsl">color.hsl</h3>
<p>Returns an array with the <code>hue</code>, <code>saturation</code>, and <code>lightness</code> component. Hue is the color angle in degree (<code>0..360</code>), saturation and lightness are within <code>0..1</code>. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).hsl();
chroma(&#39;white&#39;).hsl();
</code></pre>
<h3 id="color-hsv">color.hsv</h3>
<p>Returns an array with the <code>hue</code>, <code>saturation</code>, and <code>value</code> components. Hue is the color angle in degree (<code>0..360</code>), saturation and value are within <code>0..1</code>. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).hsv();
chroma(&#39;white&#39;).hsv();
</code></pre>
<h3 id="color-hsi">color.hsi</h3>
<p>Returns an array with the <code>hue</code>, <code>saturation</code>, and <code>intensity</code> components, each as number between 0 and 255. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).hsi();
chroma(&#39;white&#39;).hsi();
</code></pre>
<h3 id="color-lab">color.lab</h3>
<p>Returns an array with the <strong>L</strong>, <strong>a</strong>, and <strong>b</strong> components.</p>
<pre><code class="lang-js">chroma(&#39;orange&#39;).lab()
</code></pre>
<h3 id="color-lch">color.lch</h3>
<p>Returns an array with the <strong>Lightness</strong>, <strong>chroma</strong>, and <strong>hue</strong> components.</p>
<pre><code class="lang-js">chroma(&#39;skyblue&#39;).lch()
</code></pre>
<h3 id="color-hcl">color.hcl</h3>
<p>Alias of <a href="#color-lch">lch</a>, but with the components in reverse order.</p>
<pre><code class="lang-js">chroma(&#39;skyblue&#39;).hcl()
</code></pre>
<h3 id="color-temperature">color.temperature</h3>
<p>Estimate the temperature in Kelvin of any given color, though this makes the only sense for colors from the <a href="#chroma-temperature">temperature gradient</a> above.</p>
<pre><code class="lang-js">chroma(&#39;#ff3300&#39;).temperature();
chroma(&#39;#ff8a13&#39;).temperature();
chroma(&#39;#ffe3cd&#39;).temperature();
chroma(&#39;#cbdbff&#39;).temperature();
chroma(&#39;#b3ccff&#39;).temperature();
</code></pre>
<h3 id="color-gl">color.gl</h3>
<p>Like RGB, but in the channel range of <code>[0..1]</code> instead of <code>[0..255]</code></p>
<pre><code class="lang-js">chroma(&#39;33cc00&#39;).gl();
</code></pre>
<h3 id="color-clipped">color.clipped</h3>
<p>When converting colors from CIELab color spaces to RGB the color channels get clipped to the range of <code>[0..255]</code>. Colors outside that range may exist in nature but are not displayable on RGB monitors (such as ultraviolet). you can use color.clipped to test if a color has been clipped or not.</p>
<pre><code class="lang-js">[c = chroma.hcl(50, 40, 20), c.clipped()];
[c = chroma.hcl(50, 40, 40), c.clipped()];
[c = chroma.hcl(50, 40, 60), c.clipped()];
[c = chroma.hcl(50, 40, 80), c.clipped()];
[c = chroma.hcl(50, 40, 100), c.clipped()];
</code></pre>
<p>As a bonus feature you can access the unclipped RGB components using <code>color._rgb._unclipped</code>.</p>
<pre><code class="lang-js">chroma.hcl(50, 40, 100).rgb();
chroma.hcl(50, 40, 100)._rgb._unclipped;
</code></pre>
<h2 id="color-scales">color scales</h2>
<h3 id="chroma-scale">chroma.scale</h3>
<h4 id="-colors-white-black-">(colors=[&#39;white&#39;,&#39;black&#39;])</h4>
<p>A color scale, created with <code>chroma.scale</code>, is a function that maps numeric values to a color palette. The default scale has the domain <code>0..1</code> and goes from white to black.</p>
<pre><code class="lang-js">f = chroma.scale();
f(0.25);
f(0.5);
f(0.75);
</code></pre>
<p>You can pass an array of colors to <code>chroma.scale</code>. Any color that can be read by <code>chroma()</code> will work here, too. If you pass more than two colors, they will be evenly distributed along the gradient.</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]);
chroma.scale([&#39;yellow&#39;, &#39;red&#39;, &#39;black&#39;]);
</code></pre>
<h3 id="scale-domain">scale.domain</h3>
<h4 id="-domain-">(domain)</h4>
<p>You can change the input domain to match your specific use case.</p>
<pre><code class="lang-js">// default domain is [0,1]
chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]);
// set domain to [0,100]
chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]).domain([0,100]);
</code></pre>
<p>You can use the domain to set the exact positions of each color.</p>
<pre><code class="lang-js">// default domain is [0,1]
chroma.scale([&#39;yellow&#39;, &#39;lightgreen&#39;, &#39;008ae5&#39;])
.domain([0,0.25,1]);
</code></pre>
<h3 id="scale-mode">scale.mode</h3>
<h4 id="-mode-">(mode)</h4>
<p>As with <code>chroma.mix</code>, the result of the color interpolation will depend on the color mode in which the channels are interpolated. The default mode is <code>RGB</code>:</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]);
</code></pre>
<p>This is often fine, but sometimes, two-color <code>RGB</code> gradients goes through kind of grayish colors, and <code>Lab</code> interpolation produces better results:</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;navy&#39;]);
chroma.scale([&#39;yellow&#39;, &#39;navy&#39;]).mode(&#39;lab&#39;);
</code></pre>
<p>Other useful interpolation modes could be <code>HSL</code> or <code>Lch</code>, though both tend to produce too saturated / glowing gradients.</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;navy&#39;]).mode(&#39;lab&#39;);
chroma.scale([&#39;yellow&#39;, &#39;navy&#39;]).mode(&#39;hsl&#39;);
chroma.scale([&#39;yellow&#39;, &#39;navy&#39;]).mode(&#39;lch&#39;);
</code></pre>
<h3 id="scale-correctlightness">scale.correctLightness</h3>
<p>Sometimes</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]).mode(&#39;lch&#39;);
chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;])
.mode(&#39;lch&#39;)
.correctLightness();
</code></pre>
<h3 id="scale-cache">scale.cache</h3>
<h4 id="-true-false-">(true|false)</h4>
<p>By default <code>chroma.scale</code> instances will cache each computed value =&gt; color pair. You can turn off the cache by setting</p>
<pre><code class="lang-js">chroma.scale([&#39;yellow&#39;, &#39;008ae5&#39;]).cache(false);
</code></pre>
<h3 id="scale-padding">scale.padding</h3>
<h4 id="-pad-">(pad)</h4>
<p>Reduces the color range by cutting of a fraction of the gradient on both sides. If you pass a single number, the same padding will be applied to both ends.</p>
<pre><code class="lang-js">chroma.scale(&#39;RdYlBu&#39;);
chroma.scale(&#39;RdYlBu&#39;).padding(0.15);
chroma.scale(&#39;RdYlBu&#39;).padding(0.3);
chroma.scale(&#39;RdYlBu&#39;).padding(-0.15);
</code></pre>
<p>Alternatively you can specify the padding for each sides individually by passing an array of two numbers.</p>
<pre><code class="lang-js">chroma.scale(&#39;OrRd&#39;);
chroma.scale(&#39;OrRd&#39;).padding([0.2, 0]);
</code></pre>
<h3 id="scale-colors">scale.colors</h3>
<h4 id="-num-format-hex-">(num, format=&#39;hex&#39;)</h4>
<p>You can call <code>scale.colors(n)</code> to quickly grab <code>n</code> equi-distant colors from a color scale. If called with no arguments, <code>scale.colors</code> returns the original array of colors used to create the scale.</p>
<pre><code class="lang-js">chroma.scale(&#39;OrRd&#39;).colors(5);
chroma.scale([&#39;white&#39;, &#39;black&#39;]).colors(12);
</code></pre>
<h3 id="scale-classes">scale.classes</h3>
<h4 id="-numorarray-">(numOrArray)</h4>
<p>If you want the scale function to return a distinct set of colors instead of a continuous gradient, you can use <code>scale.classes</code>. If you pass a number the scale will broken into equi-distant classes:</p>
<pre><code class="lang-js">// continuous
chroma.scale(&#39;OrRd&#39;);
// class breaks
chroma.scale(&#39;OrRd&#39;).classes(5);
chroma.scale(&#39;OrRd&#39;).classes(8);
</code></pre>
<p>You can also define custom class breaks by passing them as array: </p>
<pre><code class="lang-js">chroma.scale(&#39;OrRd&#39;).classes([0,0.3,0.55,0.85,1]);
</code></pre>
<h3 id="chroma-brewer">chroma.brewer</h3>
<p>chroma.js includes the definitions from <a href="http://colorbrewer2.org/">ColorBrewer2.org</a>. Read more about these colors <a href="http://www.albany.edu/faculty/fboscoe/papers/harrower2003.pdf">in the corresponding paper</a> by Mark Harrower and Cynthia A. Brewer.</p>
<pre><code class="lang-js">chroma.scale(&#39;YlGnBu&#39;);
chroma.scale(&#39;Spectral&#39;);
</code></pre>
<p>To reverse the colors you could simply reverse the domain:</p>
<pre><code class="lang-js">chroma.scale(&#39;Spectral&#39;).domain([1,0]);
</code></pre>
<p>You can access the colors directly using <code>chroma.brewer</code>.</p>
<pre><code class="lang-js">chroma.brewer.OrRd
</code></pre>
<h3 id="chroma-bezier">chroma.bezier</h3>
<h4 id="-colors-">(colors)</h4>
<p><code>chroma.bezier</code> returns a function that <a href="https://www.vis4.net/blog/posts/mastering-multi-hued-color-scales/">bezier-interpolates between colors</a> in <code>Lab</code> space. The input range of the function is <code>[0..1]</code>.</p>
<pre><code class="lang-js">// linear interpolation
chroma.scale([&#39;yellow&#39;, &#39;red&#39;, &#39;black&#39;]);
// bezier interpolation
chroma.bezier([&#39;yellow&#39;, &#39;red&#39;, &#39;black&#39;]);
</code></pre>
<p>You can convert an bezier interpolator into a chroma.scale instance</p>
<pre><code class="lang-js">chroma.bezier([&#39;yellow&#39;, &#39;red&#39;, &#39;black&#39;])
.scale()
.colors(5);
</code></pre>
<h2 id="cubehelix">cubehelix</h2>
<h3 id="chroma-cubehelix">chroma.cubehelix</h3>
<h4 id="-start-300-rotations-1-5-hue-1-gamma-1-lightness-0-1-">(start=300, rotations=-1.5, hue=1, gamma=1, lightness=[0,1])</h4>
<p>Dave Green&#39;s <a href="http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/">cubehelix color scheme</a>!!</p>
<pre><code class="lang-js">// use the default helix...
chroma.cubehelix();
// or customize it
chroma.cubehelix()
.start(200)
.rotations(-0.5)
.gamma(0.8)
.lightness([0.3, 0.8]);
</code></pre>
<h3 id="cubehelix-start">cubehelix.start</h3>
<h4 id="-hue-">(hue)</h4>
<p><strong>start</strong> color for <a href="http://en.wikipedia.org/wiki/Hue#/media/File:HueScale.svg">hue rotation</a>, default=<code>300</code></p>
<pre><code class="lang-js">chroma.cubehelix().start(300);
chroma.cubehelix().start(200);
</code></pre>
<h3 id="cubehelix-rotations">cubehelix.rotations</h3>
<h4 id="-num-">(num)</h4>
<p>number (and direction) of hue rotations (e.g. 1=<code>360°</code>, 1.5=`540°``), default=-1.5</p>
<pre><code class="lang-js">chroma.cubehelix().rotations(-1.5);
chroma.cubehelix().rotations(0.5);
chroma.cubehelix().rotations(3);
</code></pre>
<h3 id="cubehelix-hue">cubehelix.hue</h3>
<h4 id="-numorrange-">(numOrRange)</h4>
<p>hue controls how saturated the colour of all hues are. either single value or range, default=1</p>
<pre><code class="lang-js">chroma.cubehelix();
chroma.cubehelix().hue(0.5);
chroma.cubehelix().hue([1,0]);
</code></pre>
<h3 id="cubehelix-gamma">cubehelix.gamma</h3>
<h4 id="-factor-">(factor)</h4>
<p>gamma factor can be used to emphasise low or high intensity values, default=1</p>
<pre><code class="lang-js">chroma.cubehelix().gamma(1);
chroma.cubehelix().gamma(0.5);
</code></pre>
<h3 id="cubehelix-lightness">cubehelix.lightness</h3>
<h4 id="-range-">(range)</h4>
<p>lightness range: default: [0,1] (black -&gt; white)</p>
<pre><code class="lang-js">chroma.cubehelix().lightness([0,1]);
chroma.cubehelix().lightness([1,0]);
chroma.cubehelix().lightness([0.3,0.7]);
</code></pre>
<h3 id="cubehelix-scale">cubehelix.scale</h3>
<p>You can call <code>cubehelix.scale()</code> to use the cube-helix through the <code>chroma.scale</code> interface.</p>
<pre><code class="lang-js">chroma.cubehelix()
.start(200)
.rotations(-0.35)
.gamma(0.7)
.lightness([0.3, 0.8])
.scale() // convert to chroma.scale
.correctLightness()
.colors(5);
</code></pre>
<link rel="stylesheet" type="text/css" href="libs/codemirror/lib/codemirror.css">
<script type="text/javascript" src="libs/jquery/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="libs/chroma.min.js"></script>
<script type="text/javascript" src="libs/codemirror/lib/codemirror.js"></script>
<script type="text/javascript" src="libs/codemirror/mode/javascript/javascript.js"></script>
<script type="text/javascript">
$('code.lang-js').each(function() {
var code = this;
var cm = CodeMirror(function(elt) {
code.parentNode.replaceChild(elt, code);
}, {
value: code.innerHTML.trim(),
indentUnit: 4,
mode: 'javascript'
});
cm.on('update', function(_cm, change) {
showColors(_cm);
});
var resDisplay = $('<div class="result-display" />')
.appendTo(cm.display.wrapper.parentNode);
showColors(cm);
function showColors(cm) {
$('.cm-string', cm.display.wrapper).each(styleSpan);
$('.cm-number', cm.display.wrapper).each(enableSlider);
// evaluate script
var src = cm.getDoc().getValue();
//resDisplay.html('');
try {
var s = src.split(';').map(eval);
resDisplay.html('<ol><li>'+s.map(resRec)
.filter(function(d) { return d !== undefined; })
.join('</li><li>')+'</li></ol>');
$('.cm-string', resDisplay).each(styleSpan);
} catch (e) {
// console.warn(e);
}
function resRec(d) {
if ($.isArray(d)) {
return '['+d.map(d.length > 2 ? resShort : resLong).join(',')+']';
}
return resLong(d);
function resLong(d) {
if (typeof d == 'boolean') {
return '<span class="cm-number">'+(d ? 'true' : 'false')+'</span>';
} else if (typeof d == 'string') {
// string color, e.g. hex value
return '<span class="cm-string">"'+d+'"</span>';
} else if (typeof d == 'object' && d._rgb) {
// chroma.js object
return '<span class="cm-string cm-color" data-color="'+d.css()+'">'+d.hex()+'</span>';
} else if ($.isNumeric(d)) {
return '<span class="cm-number">'+round(d,3)+'</span>';
} else if ($.isFunction(d)) {
var s = '';
var dom = d.domain ? d.domain() : [0,1],
dmin = Math.min(dom[0], dom[dom.length-1]),
dmax = Math.max(dom[dom.length-1], dom[0]);
for (var i=0;i<=100;i++) {
s += '<span class="grad-step" style="background-color:'+d(dmin + i/100 * (dmax - dmin))+'"></span>';
}
s += '<span class="domain-min">'+dmin+'</span>';
s += '<span class="domain-med">'+((dmin + dmax)*0.5)+'</span>';
s += '<span class="domain-max">'+dmax+'</span>';
return '<div class="gradient">'+s+'</div>';
}
}
function resShort(d) {
if (typeof d == 'string') {
// string color, e.g. hex value
return '<span class="cm-string cm-color cm-small" data-color="'+d+'"><span class="cm-hidden-text">\''+chroma(d).hex()+'\'</span></span>';
} else if (typeof d == 'object' && d._rgb) {
// chroma.js object
return '<span class="cm-string cm-color cm-small" data-color="'+d.css()+'"><span class="cm-hidden-text">\''+d.hex()+'\'</span></span>';
} else if ($.isNumeric(d)) {
return '<span class="cm-number">'+round(d,2)+'</span>';
} else if (isNaN(d)) {
return '<span class="cm-number cm-nan">NaN</span>';
}
}
function round(d, p) {
var n = Math.pow(10, p);
return Math.round(d*n) / n;
}
}
}
function styleSpan() {
var span = $(this);
//setTimeout(function() {
val = span.data('color') || span.html().replace(/['"]/g, '').trim();
if (chroma[val]) {
span.attr('style', '');
return;
}
try {
var col = chroma(val),
l = col.luminance();
span.attr('style', [
'background-color:'+col.hex(),
'color:'+(l <0.5 ? 'white' : 'black'),
'opacity:'+col.alpha()
].join(';'));
} catch (e) {
//console.log(e);
span.attr('style', '');
// not a color, so ignore
}
//}, 50);
}
function enableSlider() {
return;
var span = $(this),
slider = $('<div></div>').addClass('slider'),
input = $('<input type="range" />').appendTo(slider);
span.off('mouseenter').on('mouseenter', function() {
var v = +span.text(),
d = Math.pow(10, Math.max(1, Math.log10(v))),
min = v - d,
max = v + d;
input.attr({ min: min, max: max })
.prop('value', v);
console.log('span', v);
span.append(slider);
});
span.off('mouseleave').on('mouseleave', function() {
//slider.remove();
});
}
});
var toc = $('<ul />')
.addClass('toc')
.appendTo(
$('<div>')
.addClass('toc-container')
.appendTo('.wrap')
);
var hue = Math.random() * 360;
$('h2,h3').each(function() {
var h = $(this),
l = h.attr('id'),
t = h.is('h2');
toc.append('<li class="'+('level-'+(t ? '1' : '2'))+'"><a style="color:'+chroma.lch(50,80,hue)+'" href="#'+l+'">' + h.text() +'</a></li>');
hue = (hue + 20) % 360;
var a = $('<a />')
.attr('href', '#'+l)
.html(h.html());
h.html('').append(a);
});
$('h3+h4').each(function(i,el) { el.previousElementSibling.appendChild(el); });
</script>
<a href="https://github.com/gka/chroma.js" class="github-corner"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#64CEAA; color:#fff; position: absolute; top: 0; border: 0; right: 0;"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
<style>
.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}
@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
</style>
</div></body>
</html>

2707
src/static/node_modules/chroma-js/docs/libs/chroma.js generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,114 @@
<!doctype html>
<title>CodeMirror: JavaScript mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="../../addon/comment/continuecomment.js"></script>
<script src="../../addon/comment/comment.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">JavaScript</a>
</ul>
</div>
<article>
<h2>JavaScript mode</h2>
<div><textarea id="code" name="code">
// Demo code (the actual new parser character stream implementation)
function StringStream(string) {
this.pos = 0;
this.string = string;
}
StringStream.prototype = {
done: function() {return this.pos >= this.string.length;},
peek: function() {return this.string.charAt(this.pos);},
next: function() {
if (this.pos &lt; this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch &amp;&amp; match.test ? match.test(ch) : match(ch);
if (ok) {this.pos++; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match));
if (this.pos > start) return this.string.slice(start, this.pos);
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.pos;},
eatSpace: function() {
var start = this.pos;
while (/\s/.test(this.string.charAt(this.pos))) this.pos++;
return this.pos - start;
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += str.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match &amp;&amp; consume !== false) this.pos += match[0].length;
return match;
}
}
};
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
continueComments: "Enter",
extraKeys: {"Ctrl-Q": "toggleComment"}
});
</script>
<p>
JavaScript mode supports several configuration options:
<ul>
<li><code>json</code> which will set the mode to expect JSON
data rather than a JavaScript program.</li>
<li><code>jsonld</code> which will set the mode to expect
<a href="http://json-ld.org">JSON-LD</a> linked data rather
than a JavaScript program (<a href="json-ld.html">demo</a>).</li>
<li><code>typescript</code> which will activate additional
syntax highlighting and some other things for TypeScript code
(<a href="typescript.html">demo</a>).</li>
<li><code>statementIndent</code> which (given a number) will
determine the amount of indentation to use for statements
continued on a new line.</li>
<li><code>wordCharacters</code>, a regexp that indicates which
characters should be considered part of an identifier.
Defaults to <code>/[\w$]/</code>, which does not handle
non-ASCII identifiers. Can be set to something more elaborate
to improve Unicode support.</li>
</ul>
</p>
<p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>application/ld+json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
</article>

View file

@ -0,0 +1,704 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// TODO actually recognize syntax of TypeScript constructs
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
var jsonldMode = parserConfig.jsonld;
var jsonMode = parserConfig.json || jsonldMode;
var isTS = parserConfig.typescript;
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "variable-3"};
var tsKeywords = {
// object-like things
"interface": kw("interface"),
"extends": kw("extends"),
"constructor": kw("constructor"),
// scope modifiers
"public": kw("public"),
"private": kw("private"),
"protected": kw("protected"),
"static": kw("static"),
// types
"string": type, "number": type, "bool": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
function readRegexp(stream) {
var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
if (!escaped) {
if (next == "/" && !inSet) return;
if (next == "[") inSet = true;
else if (inSet && next == "]") inSet = false;
}
escaped = !escaped && next == "\\";
}
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
return ret("number", "number");
} else if (ch == "." && stream.match("..")) {
return ret("spread", "meta");
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
} else if (ch == "=" && stream.eat(">")) {
return ret("=>", "operator");
} else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
} else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
} else if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
} else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2");
} else {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
}
} else if (ch == "`") {
state.tokenize = tokenQuasi;
return tokenQuasi(stream, state);
} else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
} else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
} else if (wordRE.test(ch)) {
stream.eatWhile(wordRE);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
ret("variable", "variable", word);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next;
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
state.tokenize = tokenBase;
return ret("jsonld-keyword", "meta");
}
while ((next = stream.next()) != null) {
if (next == quote && !escaped) break;
escaped = !escaped && next == "\\";
}
if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
function tokenQuasi(stream, state) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
state.tokenize = tokenBase;
break;
}
escaped = !escaped && next == "\\";
}
return ret("quasi", "string-2", stream.current());
}
var brackets = "([{}])";
// This is a crude lookahead trick to try and notice that we're
// parsing the argument patterns for a fat-arrow function before we
// actually hit the arrow token. It only works if the arrow is on
// the same line as the arguments and there's no strange noise
// (comments) in between. Fallback is to only notice when we hit the
// arrow, and not declare the arguments as locals for the arrow
// body.
function findFatArrow(stream, state) {
if (state.fatArrowAt) state.fatArrowAt = null;
var arrow = stream.string.indexOf("=>", stream.start);
if (arrow < 0) return;
var depth = 0, sawSomething = false;
for (var pos = arrow - 1; pos >= 0; --pos) {
var ch = stream.string.charAt(pos);
var bracket = brackets.indexOf(ch);
if (bracket >= 0 && bracket < 3) {
if (!depth) { ++pos; break; }
if (--depth == 0) break;
} else if (bracket >= 3 && bracket < 6) {
++depth;
} else if (wordRE.test(ch)) {
sawSomething = true;
} else if (/["'\/]/.test(ch)) {
return;
} else if (sawSomething && !depth) {
++pos;
break;
}
}
if (sawSomething && !depth) state.fatArrowAt = pos;
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
for (var cx = state.context; cx; cx = cx.prev) {
for (var v = cx.vars; v; v = v.next)
if (v.name == varname) return true;
}
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
function inList(list) {
for (var v = list; v; v = v.next)
if (v.name == varname) return true;
return false;
}
var state = cx.state;
if (state.context) {
cx.marked = "def";
if (inList(state.localVars)) return;
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
if (parserConfig.globalVars)
state.globalVars = {name: varname, next: state.globalVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
cx.state.localVars = defaultVars;
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state, indent = state.indented;
if (state.lexical.type == "stat") indent = state.lexical.indented;
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
indent = outer.indented;
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
function exp(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(exp);
};
return exp;
}
function statement(type, value) {
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "if") {
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
cx.state.cc.pop()();
return cont(pushlex("form"), expression, statement, poplex, maybeelse);
}
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("form"), afterExport, poplex);
if (type == "import") return cont(pushlex("form"), afterImport, poplex);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
}
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
}
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop);
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
if (type == "quasi") { return pass(quasi, maybeop); }
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
function maybeexpressionNoComma(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expressionNoComma);
}
function maybeoperatorComma(type, value) {
if (type == ",") return cont(expression);
return maybeoperatorNoComma(type, value, false);
}
function maybeoperatorNoComma(type, value, noComma) {
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
var expr = noComma == false ? expression : expressionNoComma;
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
if (type == "operator") {
if (/\+\+|--/.test(value)) return cont(me);
if (value == "?") return cont(expression, expect(":"), expr);
return cont(expr);
}
if (type == "quasi") { return pass(quasi, me); }
if (type == ";") return;
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
}
function quasi(type, value) {
if (type != "quasi") return pass();
if (value.slice(value.length - 2) != "${") return cont(quasi);
return cont(expression, continueQuasi);
}
function continueQuasi(type) {
if (type == "}") {
cx.marked = "string-2";
cx.state.tokenize = tokenQuasi;
return cont(quasi);
}
}
function arrowBody(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expression);
}
function arrowBodyNoComma(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expressionNoComma);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type, value) {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
return cont(afterprop);
} else if (type == "number" || type == "string") {
cx.marked = jsonldMode ? "property" : (cx.style + " property");
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
}
}
function getterSetter(type) {
if (type != "variable") return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
function afterprop(type) {
if (type == ":") return cont(expressionNoComma);
if (type == "(") return pass(functiondef);
}
function commasep(what, end) {
function proceed(type) {
if (type == ",") {
var lex = cx.state.lexical;
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
return cont(what, proceed);
}
if (type == end) return cont();
return cont(expect(end));
}
return function(type) {
if (type == end) return cont();
return pass(what, proceed);
};
}
function contCommasep(what, end, info) {
for (var i = 3; i < arguments.length; i++)
cx.cc.push(arguments[i]);
return cont(pushlex(end, info), commasep(what, end), poplex);
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type) {
if (isTS && type == ":") return cont(typedef);
}
function maybedefault(_, value) {
if (value == "=") return cont(expressionNoComma);
}
function typedef(type) {
if (type == "variable") {cx.marked = "variable-3"; return cont();}
}
function vardef() {
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "variable") { register(value); return cont(); }
if (type == "[") return contCommasep(pattern, "]");
if (type == "{") return contCommasep(proppattern, "}");
}
function proppattern(type, value) {
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
register(value);
return cont(maybeAssign);
}
if (type == "variable") cx.marked = "property";
return cont(expect(":"), pattern, maybeAssign);
}
function maybeAssign(_type, value) {
if (value == "=") return cont(expressionNoComma);
}
function vardefCont(type) {
if (type == ",") return cont(vardef);
}
function maybeelse(type, value) {
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
}
function forspec(type) {
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
}
function forspec1(type) {
if (type == "var") return cont(vardef, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
if (type == "variable") return cont(formaybeinof);
return pass(expression, expect(";"), forspec2);
}
function formaybeinof(_type, value) {
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
}
function funarg(type) {
if (type == "spread") return cont(funarg);
return pass(pattern, maybetype, maybedefault);
}
function className(type, value) {
if (type == "variable") {register(value); return cont(classNameAfter);}
}
function classNameAfter(type, value) {
if (value == "extends") return cont(expression, classNameAfter);
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
if (type == "variable" || cx.style == "keyword") {
if (value == "static") {
cx.marked = "keyword";
return cont(classBody);
}
cx.marked = "property";
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
return cont(functiondef, classBody);
}
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);
}
if (type == ";") return cont(classBody);
if (type == "}") return cont();
}
function classGetterSetter(type) {
if (type != "variable") return pass();
cx.marked = "property";
return cont();
}
function afterModule(type, value) {
if (type == "string") return cont(statement);
if (type == "variable") { register(value); return cont(maybeFrom); }
}
function afterExport(_type, value) {
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
return pass(statement);
}
function afterImport(type) {
if (type == "string") return cont();
return pass(importSpec, maybeFrom);
}
function importSpec(type, value) {
if (type == "{") return contCommasep(importSpec, "}");
if (type == "variable") register(value);
if (value == "*") cx.marked = "keyword";
return cont(maybeAs);
}
function maybeAs(_type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
}
function maybeFrom(_type, value) {
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
}
function arrayLiteral(type) {
if (type == "]") return cont();
return pass(expressionNoComma, maybeArrayComprehension);
}
function maybeArrayComprehension(type) {
if (type == "for") return pass(comprehension, expect("]"));
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
return pass(commasep(expressionNoComma, "]"));
}
function comprehension(type) {
if (type == "for") return cont(forspec, comprehension);
if (type == "if") return cont(expression, comprehension);
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," ||
isOperatorChar.test(textAfter.charAt(0)) ||
/[,.]/.test(textAfter.charAt(0));
}
// Interface
return {
startState: function(basecolumn) {
var state = {
tokenize: tokenBase,
lastType: "sof",
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
state.globalVars = parserConfig.globalVars;
return state;
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
findFatArrow(stream, state);
}
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize == tokenComment) return CodeMirror.Pass;
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
// Kludge to prevent 'maybelse' from blocking lexical scope pops
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex) lexical = lexical.prev;
else if (c != maybeelse) break;
}
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
blockCommentStart: jsonMode ? null : "/*",
blockCommentEnd: jsonMode ? null : "*/",
lineComment: jsonMode ? null : "//",
fold: "brace",
closeBrackets: "()[]{}''\"\"``",
helperType: jsonMode ? "json" : "javascript",
jsonldMode: jsonldMode,
jsonMode: jsonMode
};
});
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/x-javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
});

View file

@ -0,0 +1,72 @@
<!doctype html>
<title>CodeMirror: JSON-LD mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="../../addon/comment/continuecomment.js"></script>
<script src="../../addon/comment/comment.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id="nav">
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"/></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">JSON-LD</a>
</ul>
</div>
<article>
<h2>JSON-LD mode</h2>
<div><textarea id="code" name="code">
{
"@context": {
"name": "http://schema.org/name",
"description": "http://schema.org/description",
"image": {
"@id": "http://schema.org/image",
"@type": "@id"
},
"geo": "http://schema.org/geo",
"latitude": {
"@id": "http://schema.org/latitude",
"@type": "xsd:float"
},
"longitude": {
"@id": "http://schema.org/longitude",
"@type": "xsd:float"
},
"xsd": "http://www.w3.org/2001/XMLSchema#"
},
"name": "The Empire State Building",
"description": "The Empire State Building is a 102-story landmark in New York City.",
"image": "http://www.civil.usherbrooke.ca/cours/gci215a/empire-state-building.jpg",
"geo": {
"latitude": "40.75",
"longitude": "73.98"
}
}
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
matchBrackets: true,
autoCloseBrackets: true,
mode: "application/ld+json",
lineWrapping: true
});
</script>
<p>This is a specialization of the <a href="index.html">JavaScript mode</a>.</p>
</article>

View file

@ -0,0 +1,205 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "javascript");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("locals",
"[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
MT("comma-and-binop",
"[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }");
MT("destructuring",
"([keyword function]([def a], [[[def b], [def c] ]]) {",
" [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);",
" [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];",
"})();");
MT("class_body",
"[keyword class] [variable Foo] {",
" [property constructor]() {}",
" [property sayName]() {",
" [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];",
" }",
"}");
MT("class",
"[keyword class] [variable Point] [keyword extends] [variable SuperThing] {",
" [property get] [property prop]() { [keyword return] [number 24]; }",
" [property constructor]([def x], [def y]) {",
" [keyword super]([string 'something']);",
" [keyword this].[property x] [operator =] [variable-2 x];",
" }",
"}");
MT("module",
"[keyword module] [string 'foo'] {",
" [keyword export] [keyword let] [def x] [operator =] [number 42];",
" [keyword export] [keyword *] [keyword from] [string 'somewhere'];",
"}");
MT("import",
"[keyword function] [variable foo]() {",
" [keyword import] [def $] [keyword from] [string 'jquery'];",
" [keyword module] [def crypto] [keyword from] [string 'crypto'];",
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
"}");
MT("const",
"[keyword function] [variable f]() {",
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
"}");
MT("for/of",
"[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}");
MT("generator",
"[keyword function*] [variable repeat]([def n]) {",
" [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
" [keyword yield] [variable-2 i];",
"}");
MT("quotedStringAddition",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
MT("quotedFatArrow",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
MT("fatArrow",
"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
"[variable a];", // No longer in scope
"[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
"[variable c];");
MT("spread",
"[keyword function] [variable f]([def a], [meta ...][def b]) {",
" [variable something]([variable-2 a], [meta ...][variable-2 b]);",
"}");
MT("comprehension",
"[keyword function] [variable f]() {",
" [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
" ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
"}");
MT("quasi",
"[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
MT("quasi_no_function",
"[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
MT("indent_statement",
"[keyword var] [variable x] [operator =] [number 10]",
"[variable x] [operator +=] [variable y] [operator +]",
" [atom Infinity]",
"[keyword debugger];");
MT("indent_if",
"[keyword if] ([number 1])",
" [keyword break];",
"[keyword else] [keyword if] ([number 2])",
" [keyword continue];",
"[keyword else]",
" [number 10];",
"[keyword if] ([number 1]) {",
" [keyword break];",
"} [keyword else] [keyword if] ([number 2]) {",
" [keyword continue];",
"} [keyword else] {",
" [number 10];",
"}");
MT("indent_for",
"[keyword for] ([keyword var] [variable i] [operator =] [number 0];",
" [variable i] [operator <] [number 100];",
" [variable i][operator ++])",
" [variable doSomething]([variable i]);",
"[keyword debugger];");
MT("indent_c_style",
"[keyword function] [variable foo]()",
"{",
" [keyword debugger];",
"}");
MT("indent_else",
"[keyword for] (;;)",
" [keyword if] ([variable foo])",
" [keyword if] ([variable bar])",
" [number 1];",
" [keyword else]",
" [number 2];",
" [keyword else]",
" [number 3];");
MT("indent_funarg",
"[variable foo]([number 10000],",
" [keyword function]([def a]) {",
" [keyword debugger];",
"};");
MT("indent_below_if",
"[keyword for] (;;)",
" [keyword if] ([variable foo])",
" [number 1];",
"[number 2];");
MT("multilinestring",
"[keyword var] [variable x] [operator =] [string 'foo\\]",
"[string bar'];");
MT("scary_regexp",
"[string-2 /foo[[/]]bar/];");
MT("indent_strange_array",
"[keyword var] [variable x] [operator =] [[",
" [number 1],,",
" [number 2],",
"]];",
"[number 10];");
MT("param_default",
"[keyword function] [variable foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
" [keyword return] [variable-2 x];",
"}");
var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}
);
function LD(name) {
test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1));
}
LD("json_ld_keywords",
'{',
' [meta "@context"]: {',
' [meta "@base"]: [string "http://example.com"],',
' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],',
' [property "likesFlavor"]: {',
' [meta "@container"]: [meta "@list"]',
' [meta "@reverse"]: [string "@beFavoriteOf"]',
' },',
' [property "nick"]: { [meta "@container"]: [meta "@set"] },',
' [property "nick"]: { [meta "@container"]: [meta "@index"] }',
' },',
' [meta "@graph"]: [[ {',
' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],',
' [property "name"]: [string "John Lennon"],',
' [property "modified"]: {',
' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],',
' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]',
' }',
' } ]]',
'}');
LD("json_ld_fake",
'{',
' [property "@fake"]: [string "@fake"],',
' [property "@contextual"]: [string "@identifier"],',
' [property "user@domain.com"]: [string "@graphical"],',
' [property "@ID"]: [string "@@ID"]',
'}');
})();

View file

@ -0,0 +1,61 @@
<!doctype html>
<title>CodeMirror: TypeScript mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="javascript.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">TypeScript</a>
</ul>
</div>
<article>
<h2>TypeScript mode</h2>
<div><textarea id="code" name="code">
class Greeter {
greeting: string;
constructor (message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
var greeter = new Greeter("world");
var button = document.createElement('button')
button.innerText = "Say Hello"
button.onclick = function() {
alert(greeter.greet())
}
document.body.appendChild(button)
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
mode: "text/typescript"
});
</script>
<p>This is a specialization of the <a href="index.html">JavaScript mode</a>.</p>
</article>

File diff suppressed because one or more lines are too long

33
src/static/node_modules/chroma-js/docs/license.coffee generated vendored Normal file
View file

@ -0,0 +1,33 @@
###*
* @license
*
* chroma.js - JavaScript library for color conversions
*
* Copyright (c) 2011-2015, Gregor Aisch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name Gregor Aisch may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
###

View file

@ -0,0 +1,181 @@
<link rel="stylesheet" type="text/css" href="libs/codemirror/lib/codemirror.css">
<script type="text/javascript" src="libs/jquery/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="libs/chroma.min.js"></script>
<script type="text/javascript" src="libs/codemirror/lib/codemirror.js"></script>
<script type="text/javascript" src="libs/codemirror/mode/javascript/javascript.js"></script>
<script type="text/javascript">
$('code.lang-js').each(function() {
var code = this;
var cm = CodeMirror(function(elt) {
code.parentNode.replaceChild(elt, code);
}, {
value: code.innerHTML.trim(),
indentUnit: 4,
mode: 'javascript'
});
cm.on('update', function(_cm, change) {
showColors(_cm);
});
var resDisplay = $('<div class="result-display" />')
.appendTo(cm.display.wrapper.parentNode);
showColors(cm);
function showColors(cm) {
$('.cm-string', cm.display.wrapper).each(styleSpan);
$('.cm-number', cm.display.wrapper).each(enableSlider);
// evaluate script
var src = cm.getDoc().getValue();
//resDisplay.html('');
try {
var s = src.split(';').map(eval);
resDisplay.html('<ol><li>'+s.map(resRec)
.filter(function(d) { return d !== undefined; })
.join('</li><li>')+'</li></ol>');
$('.cm-string', resDisplay).each(styleSpan);
} catch (e) {
// console.warn(e);
}
function resRec(d) {
if ($.isArray(d)) {
return '['+d.map(d.length > 2 ? resShort : resLong).join(',')+']';
}
return resLong(d);
function resLong(d) {
if (typeof d == 'boolean') {
return '<span class="cm-number">'+(d ? 'true' : 'false')+'</span>';
} else if (typeof d == 'string') {
// string color, e.g. hex value
return '<span class="cm-string">"'+d+'"</span>';
} else if (typeof d == 'object' && d._rgb) {
// chroma.js object
return '<span class="cm-string cm-color" data-color="'+d.css()+'">'+d.hex()+'</span>';
} else if ($.isNumeric(d)) {
return '<span class="cm-number">'+round(d,3)+'</span>';
} else if ($.isFunction(d)) {
var s = '';
var dom = d.domain ? d.domain() : [0,1],
dmin = Math.min(dom[0], dom[dom.length-1]),
dmax = Math.max(dom[dom.length-1], dom[0]);
for (var i=0;i<=100;i++) {
s += '<span class="grad-step" style="background-color:'+d(dmin + i/100 * (dmax - dmin))+'"></span>';
}
s += '<span class="domain-min">'+dmin+'</span>';
s += '<span class="domain-med">'+((dmin + dmax)*0.5)+'</span>';
s += '<span class="domain-max">'+dmax+'</span>';
return '<div class="gradient">'+s+'</div>';
}
}
function resShort(d) {
if (typeof d == 'string') {
// string color, e.g. hex value
return '<span class="cm-string cm-color cm-small" data-color="'+d+'"><span class="cm-hidden-text">\''+chroma(d).hex()+'\'</span></span>';
} else if (typeof d == 'object' && d._rgb) {
// chroma.js object
return '<span class="cm-string cm-color cm-small" data-color="'+d.css()+'"><span class="cm-hidden-text">\''+d.hex()+'\'</span></span>';
} else if ($.isNumeric(d)) {
return '<span class="cm-number">'+round(d,2)+'</span>';
} else if (isNaN(d)) {
return '<span class="cm-number cm-nan">NaN</span>';
}
}
function round(d, p) {
var n = Math.pow(10, p);
return Math.round(d*n) / n;
}
}
}
function styleSpan() {
var span = $(this);
//setTimeout(function() {
val = span.data('color') || span.html().replace(/['"]/g, '').trim();
if (chroma[val]) {
span.attr('style', '');
return;
}
try {
var col = chroma(val),
l = col.luminance();
span.attr('style', [
'background-color:'+col.hex(),
'color:'+(l <0.5 ? 'white' : 'black'),
'opacity:'+col.alpha()
].join(';'));
} catch (e) {
//console.log(e);
span.attr('style', '');
// not a color, so ignore
}
//}, 50);
}
function enableSlider() {
return;
var span = $(this),
slider = $('<div></div>').addClass('slider'),
input = $('<input type="range" />').appendTo(slider);
span.off('mouseenter').on('mouseenter', function() {
var v = +span.text(),
d = Math.pow(10, Math.max(1, Math.log10(v))),
min = v - d,
max = v + d;
input.attr({ min: min, max: max })
.prop('value', v);
console.log('span', v);
span.append(slider);
});
span.off('mouseleave').on('mouseleave', function() {
//slider.remove();
});
}
});
var toc = $('<ul />')
.addClass('toc')
.appendTo(
$('<div>')
.addClass('toc-container')
.appendTo('.wrap')
);
var hue = Math.random() * 360;
$('h2,h3').each(function() {
var h = $(this),
l = h.attr('id'),
t = h.is('h2');
toc.append('<li class="'+('level-'+(t ? '1' : '2'))+'"><a style="color:'+chroma.lch(50,80,hue)+'" href="#'+l+'">' + h.text() +'</a></li>');
hue = (hue + 20) % 360;
var a = $('<a />')
.attr('href', '#'+l)
.html(h.html());
h.html('').append(a);
});
$('h3+h4').each(function(i,el) { el.previousElementSibling.appendChild(el); });
</script>
<a href="https://github.com/gka/chroma.js" class="github-corner"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#64CEAA; color:#fff; position: absolute; top: 0; border: 0; right: 0;"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
<style>
.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}
@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
</style>

288
src/static/node_modules/chroma-js/docs/src/index.css generated vendored Normal file
View file

@ -0,0 +1,288 @@
@import 'https://fonts.googleapis.com/css?family=Roboto:100,300,400,700';
body {
font-family: -apple-system, BlinkMacSystemFont, 'Roboto', "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
.wrap {
max-width: 1000px;
margin: 0 auto;
}
.wrap > h1, .wrap > h2, .wrap > h3, .wrap > h4, .wrap > p, .wrap > pre, .wrap > ul {
position: relative;
/*left: -80px;*/
padding-left: 300px;
}
.wrap > h2,
.wrap > h3 {
padding-top: 10px;
}
.wrap > h2 a,
.wrap > h3 a {
color: #000;
text-decoration: none;
}
.wrap > h2 a:hover:before,
.wrap > h3 a:hover:before {
content: '#';
color: #ddd;
position: absolute;
left: 280px;
}
.wrap > ul {
margin-left: 30px;
}
.wrap > p {
margin-right: 200px;
}
ul.toc {
position: absolute;
top: 90px;
width: 200px;
list-style: none;
}
.toc li a {
text-decoration: none;
margin-bottom: 5px;
font-size: 13px;
border-bottom: 1px dotted white;
padding-bottom: 5px;
display: block;
position: relative;
}
.toc li.level-1 a {
margin-top: 15px;
font-weight: bold;
font-size: 17px;
}
.toc li.level-2 a {
padding-left: 20px;
font-size: 15px;
}
.toc li.level-2 a:before {
position: absolute;
left: 5px;
top: -2px;
font-size: 18px;
opacity: 0.3;
content: '•';
}
.wrap > h1 {
font-weight: 100;
font-size: 48px;
letter-spacing: -2px;
}
.wrap > h2 {
padding-top: 30px;
margin-top: 20px;
}
.wrap > h3 h4 {
font-weight: 400;
display: inline-block;
color: #999;
margin: 0 0 0 3px;
}
.wrap p code, .wrap li code {
font-size: 15px;
margin-left: 2px;
margin-right: 2px;
color: #069;
}
html .cm-s-default .cm-comment {
color: #B3A9A9;
font-style: italic;
}
pre {
position: relative;
margin-top: 30px;
margin-bottom: 30px;
}
pre .CodeMirror {
height: auto;
font-size: 16px;
line-height: 22px;
background: #f9f9f9;
box-shadow: inset 2px 2px 6px rgba(0,0,0,.1);
border-radius: 10px;
margin: -5px;
padding: 5px;
margin-right: 200px;
margin-bottom: 20px;
}
pre .CodeMirror:hover, pre .CodeMirror:focus {
background: #f6f6f0;
}
.result-display {
position: absolute;
right: 0px;
top: 4px;
width: 180px;
white-space: normal;
line-height: 22px;
}
.result-display .cm-string {
padding: 0px 4px;
display: inline-block;
min-width: 13px;
min-height: 13px;
border-radius: 3px;
box-sizing: border-box;
position: relative;
vertical-align: middle;
margin-left: 2px;
margin-bottom: 2px;
position: relative;
top: 1px;
}
.result-display .cm-string:before {
content: " ";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: url(../assets/bg.png);
opacity: 0.99;
z-index: -10;
}
.result-display li {
line-height: 24px;
}
.result-display .cm-number {
color: #164;
}
.CodeMirror, .CodeMirror .CodeMirror-scroll {
overflow: visible!important;
}
.CodeMirror .cm-number {
position: relative;
}
.CodeMirror .cm-number .slider {
position: absolute;
left: 50%;
top: -15px;
}
.CodeMirror .cm-number .slider input[type="range"] {
position: absolute;
left: -50px;
top: 0px;
width: 100px;
}
.result-display .cm-nan {
color: #614;
}
.result-display ol {
padding: 0;
margin: 0;
counter-reset: commands;
}
.result-display ol li {
list-style-position: inside;
list-style: none;
position: relative;
}
.result-display ol li:before {
content: '';
counter-increment: commands;
padding-right: 0px;
position: absolute;
left: -10px;
top: 2px;
color: #bbb;
}
.result-display:before {
content: "RESULT";
position: absolute;
left: 0;
top: -25px;
font-size: 11px;
color: #ccc;
}
.gradient {
width: 85%;
white-space: nowrap;
position: relative;
display: inline-block;
top: 4px;
padding-bottom: 15px;
}
.gradient .domain-min {
position: absolute;
left: 0;
font-size: 11px;
bottom: 3px;
}
.gradient .domain-med {
position: absolute;
right: 25%;
left: 25%;
text-align: center;
font-size: 11px;
bottom: 3px;
}
.gradient .domain-max {
position: absolute;
right: 0;
font-size: 11px;
bottom: 3px;
}
.grad-step {
display: inline-block;
height: 20px;
width: 1%;
}
.cm-small {
height: 15px;
width: 15px;
}
.cm-hidden-text {
display:inline-block;
width:1px;
// height:0px;
opacity: 0;
overflow:hidden;
}

815
src/static/node_modules/chroma-js/docs/src/index.md generated vendored Normal file
View file

@ -0,0 +1,815 @@
# chroma.js
**chroma.js** is a tiny JavaScript library (14kB) for dealing with colors!
[![Build Status](https://travis-ci.org/gka/chroma.js.svg?branch=master)](https://travis-ci.org/gka/chroma.js)
## Quick-start
Here are a couple of things chroma.js can do for you:
* read colors from a wide range of formats
* analyze and manipulate colors
* convert colors into wide range of formats
* linear and bezier interpolation in different color spaces
Here's an example for a simple read / manipulate / output chain:
```js
chroma('pink').darken().saturate(2).hex()
```
Aside from that, chroma.js can also help you **generate nice colors** using various methods, for instance to be [used](https://www.vis4.net/blog/posts/avoid-equidistant-hsv-colors/) in color palette for maps or data visualization.
```js
chroma.scale(['#fafa6e','#2A4858'])
.mode('lch').colors(6)
```
chroma.js has a lot more to offer, but that's the gist of it.
## API
### chroma
#### (*color*)
The first step is to get your color into chroma.js. That's what the generic constructor ``chroma()`` does. The function is trying to guess the color format for you. For instances, it will recognized any named color from the W3CX11 specification:
```js
chroma('hotpink')
```
If there's no matching named color chroma.js checks for a **hexadecimal string**. It ignores case, the `#` sign is optional, and the shorter three letter format is recognized as well. So any of these are valid hexadecimal representations: `#ff3399`, `FF3399`, `#f39`, etc.
```js
chroma('#ff3399');
chroma('F39');
```
In addition to hex strings, **hexadecimal numbers** (in fact, just any number between `0` and `16777215`), will be recognized, too.
```js
chroma(0xff3399)
```
If you pass the RGB channels individually, too. Each parameter must be within `0..255`. You can pass the numbers as individual arguments or as array.
```js
chroma(0xff, 0x33, 0x99);
chroma(255, 51, 153);
chroma([255, 51, 153]);
```
You can construct colors from different color spaces by passing the name of color space as the last argument. Here we define the same color in HSL by passing the h*ue angle (0-360) and percentages for *s*aturation and *l*ightness:
```js
chroma(330, 1, 0.6, 'hsl')
```
### chroma.hsl
#### (hue, saturation, lightness)
Alternatively, every color space has its own constructor function under the `chroma` namespace. For a list of all supported color spaces, check the [appendix](#supported-color-spaces-and-output-formats).
```js
chroma.hsl(330, 1, 0.6)
```
### chroma.hsv
#### (hue, saturation, value)
### chroma.lab
#### (Lightness, a, b)
### chroma.lch
#### (Lightness, chroma, hue)
The range for `lightness` and `chroma` depend on the hue, but go roughly from 0..100-150. The range for `hue` is 0..360.
```js
chroma.lch(80, 40, 130);
chroma(80, 40, 130, 'lch');
```
### chroma.hcl
#### (hue, chroma, lightness)
You can use **hcl** instead of Lch. Lightness and hue channels are switched to be more consistent with HSL.
```js
chroma.hcl(130, 40, 80);
chroma(130, 40, 80, 'hcl');
```
### chroma.cmyk
#### (cyan, magenta, yellow, black)
Each between 0 and 1.
```js
chroma.cmyk(0.2, 0.8, 0, 0);
chroma(0.2, 0.8, 0, 0, 'cmyk');
```
### chroma.gl
#### (red, green, blue, [alpha])
**GL** is a variant of RGB(A), with the only difference that the components are normalized to the range of `0..1`.
```js
chroma.gl(0.6, 0, 0.8);
chroma.gl(0.6, 0, 0.8, 0.5);
chroma(0.6, 0, 0.8, 'gl');
```
### chroma.temperature
#### (K)
Returns a color from the [color temperature](http://www.zombieprototypes.com/?p=210) scale. Based on [Neil Bartlett's implementation](https://github.com/neilbartlett/color-temperature).
```js
chroma.temperature(2000); // candle light
chroma.temperature(3500); // sunset
chroma.temperature(6500); // daylight
```
The effective temperature range goes from `0` to about `30000` Kelvin,
```js
f = function(i) {
return chroma.temperature(i * 30000)
}
```
### chroma.mix
#### (color1, color2, ratio=0.5, mode='rgb')
Mixes two colors. The mix *ratio* is a value between 0 and 1.
```js
chroma.mix('red', 'blue');
chroma.mix('red', 'blue', 0.25);
chroma.mix('red', 'blue', 0.75);
```
The color mixing produces different results based the color space used for interpolation.
```js
chroma.mix('red', 'blue', 0.5, 'rgb');
chroma.mix('red', 'blue', 0.5, 'hsl');
chroma.mix('red', 'blue', 0.5, 'lab');
chroma.mix('red', 'blue', 0.5, 'lch');
```
### chroma.average
#### (colors, mode='rgb')
Similar to `chroma.mix`, but accepts more than two colors. Simple averaging of R,G,B components and the alpha channel.
```js
colors = ['#ddd', 'yellow', 'red', 'teal'];
chroma.average(colors);
chroma.average(colors, 'lab');
chroma.average(colors, 'lch');
```
Also works with alpha channels.
```js
chroma.average(['red', 'rgba(0,0,0,0.5)']).css();
```
### chroma.blend
#### (color1, color2, mode)
Blends two colors using RGB channel-wise blend functions. Valid blend modes are `multiply`, `darken`, `lighten`, `screen`, `overlay`, `burn`, and `dogde`.
```js
chroma.blend('4CBBFC', 'EEEE22', 'multiply');
chroma.blend('4CBBFC', 'EEEE22', 'darken');
chroma.blend('4CBBFC', 'EEEE22', 'lighten');
```
### chroma.random
#### ()
Returns a random color.
```js
chroma.random();
chroma.random();
chroma.random();
```
### chroma.contrast
#### (color1, color2)
Computes the WCAG contrast ratio between two colors. A minimum contrast of 4.5:1 [is recommended](http://www.w3.org/TR/WCAG20-TECHS/G18.html) to ensure that text is still readable against a background color.
```js
// contrast smaller than 4.5 = too low
chroma.contrast('pink', 'hotpink');
// contrast greater than 4.5 = high enough
chroma.contrast('pink', 'purple');
```
### chroma.distance
#### (color1, color2, mode='lab')
Computes the [eucledian distance](https://en.wikipedia.org/wiki/Euclidean_distance#Three_dimensions) between two colors in a given color space (default is `Lab`).
```js
chroma.distance('#fff', '#ff0', 'rgb');
chroma.distance('#fff', '#f0f', 'rgb');
chroma.distance('#fff', '#ff0');
chroma.distance('#fff', '#f0f');
```
### chroma.deltaE
#### (reference, sample, L=1, C=1)
Computes [color difference](https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_.281984.29) as developed by the Colour Measurement Committee of the Society of Dyers and Colourists (CMC) in 1984. The implementation is adapted from [Bruce Lindbloom](https://web.archive.org/web/20160306044036/http://www.brucelindbloom.com/javascript/ColorDiff.js). The parameters L and C are weighting factors for lightness and chromacity.
```js
chroma.deltaE('#ededee', '#edeeed');
chroma.deltaE('#ececee', '#eceeec');
chroma.deltaE('#e9e9ee', '#e9eee9');
chroma.deltaE('#e4e4ee', '#e4eee4');
chroma.deltaE('#e0e0ee', '#e0eee0');
```
### chroma.brewer
chroma.brewer is an map of ColorBrewer scales that are included in chroma.js for convenience. chroma.scale uses the colors to construct.
```js
chroma.brewer.OrRd
```
### chroma.limits
#### (data, mode, n)
A helper function that computes class breaks for you, based on data. It supports the modes _equidistant_ (e), _quantile_ (q), _logarithmic_ (l), and _k-means_ (k). Let's take a few numbers as sample data.
```js
var data = [2.0,3.5,3.6,3.8,3.8,4.1,4.3,4.4,
4.6,4.9,5.2,5.3,5.4,5.7,5.8,5.9,
6.2,6.5,6.8,7.2,8];
```
**equidistant** breaks are computed by dividing the total range of the data into _n_ groups of equal size.
```js
chroma.limits(data, 'e', 4);
```
In the **quantile** mode, the input domain is divided by quantile ranges.
```js
chroma.limits(data, 'q', 4);
```
**logarithmic** breaks are equidistant breaks but on a logarithmic scale.
```js
chroma.limits(data, 'l', 4);
```
**k-means** break is using the 1-dimensional [k-means clustering](https://en.wikipedia.org/wiki/K-means_clustering) algorithm to find (roughly) _n_ groups of "similar" values. Note that this k-means implementation does not guarantee to find exactly _n_ groups.
```js
chroma.limits(data, 'k', 4);
```
## color
### color.alpha
#### (a)
Get and set the color opacity using ``color.alpha``.
```js
chroma('red').alpha(0.5);
chroma('rgba(255,0,0,0.35)').alpha();
```
### color.darken
#### (value=1)
Once loaded, chroma.js can change colors. One way we already saw above, you can change the lightness.
```js
chroma('hotpink').darken();
chroma('hotpink').darken(2);
chroma('hotpink').darken(2.6);
```
### color.brighten
#### (value=1)
Similar to `darken`, but the opposite direction
```js
chroma('hotpink').brighten();
chroma('hotpink').brighten(2);
chroma('hotpink').brighten(3);
```
### color.saturate
#### (value=1)
Changes the saturation of a color by manipulating the Lch chromacity.
```js
chroma('slategray').saturate();
chroma('slategray').saturate(2);
chroma('slategray').saturate(3);
```
### color.desaturate
#### (value=1)
Similar to `saturate`, but the opposite direction.
```js
chroma('hotpink').desaturate();
chroma('hotpink').desaturate(2);
chroma('hotpink').desaturate(3);
```
### color.set
#### (channel, value)
Changes a single channel and returns the result a new `chroma` object.
```js
// change hue to 0 deg (=red)
chroma('skyblue').set('hsl.h', 0);
// set chromacity to 30
chroma('hotpink').set('lch.c', 30);
```
Relative changes work, too:
```js
// half Lab lightness
chroma('orangered').set('lab.l', '*0.5');
// double Lch saturation
chroma('darkseagreen').set('lch.c', '*2');
```
### color.get
#### (channel)
Returns a single channel value.
```js
chroma('orangered').get('lab.l');
chroma('orangered').get('hsl.l');
chroma('orangered').get('rgb.g');
```
### color.luminance
#### ([lum, mode='rgb'])
If called without arguments color.luminance returns the relative brightness, according to the [WCAG definition](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef). Normalized to `0` for darkest black and `1` for lightest white.
```js
chroma('white').luminance();
chroma('aquamarine').luminance();
chroma('hotpink').luminance();
chroma('darkslateblue').luminance();
chroma('black').luminance();
```
chroma.js also allows you to **adjust the luminance** of a color. The source color will be interpolated with black or white until the correct luminance is found.
```js
// set lumincance to 50% for all colors
chroma('white').luminance(0.5);
chroma('aquamarine').luminance(0.5);
chroma('hotpink').luminance(0.5);
chroma('darkslateblue').luminance(0.5);
```
By default, this interpolation is done in RGB, but you can interpolate in different color spaces by passing them as second argument:
```js
chroma('aquamarine').luminance(0.5); // rgb
chroma('aquamarine').luminance(0.5, 'lab');
chroma('aquamarine').luminance(0.5, 'hsl');
```
### color.hex
Finally, chroma.js allows you to output colors in various color spaces and formats.
Most often you will want to output the color as hexadecimal string.
```js
chroma('orange').hex()
```
### color.name
Returns the named color. Falls back to hexadecimal RGB string, if the color isn't present.
```js
chroma('#ffa500').name();
chroma('#ffa505').name();
```
### color.css
Returns a `RGB()` or `HSL()` string representation that can be used as CSS-color definition.
```js
chroma('teal').css();
chroma('teal').alpha(0.5).css();
chroma('teal').css('hsl');
```
### color.rgb
#### (round=true)
Returns an array with the `red`, `green`, and `blue` component, each as number within the range `0..255`. Chroma internally stores RGB channels as floats but rounds the numbers before returning them. You can pass `false` to prevent the rounding.
```js
chroma('orange').rgb();
chroma('orange').darken().rgb();
chroma('orange').darken().rgb(false);
```
### color.rgba
#### (round=true)
Just like `color.rgb` but adds the alpha channel to the returned array.
```js
chroma('orange').rgba();
chroma('hsla(20, 100%, 40%, 0.5)').rgba();
```
### color.hsl
Returns an array with the `hue`, `saturation`, and `lightness` component. Hue is the color angle in degree (`0..360`), saturation and lightness are within `0..1`. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.
```js
chroma('orange').hsl();
chroma('white').hsl();
```
### color.hsv
Returns an array with the `hue`, `saturation`, and `value` components. Hue is the color angle in degree (`0..360`), saturation and value are within `0..1`. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.
```js
chroma('orange').hsv();
chroma('white').hsv();
```
### color.hsi
Returns an array with the `hue`, `saturation`, and `intensity` components, each as number between 0 and 255. Note that for hue-less colors (black, white, and grays), the hue component will be NaN.
```js
chroma('orange').hsi();
chroma('white').hsi();
```
### color.lab
Returns an array with the **L**, **a**, and **b** components.
```js
chroma('orange').lab()
```
### color.lch
Returns an array with the **Lightness**, **chroma**, and **hue** components.
```js
chroma('skyblue').lch()
```
### color.hcl
Alias of [lch](#color-lch), but with the components in reverse order.
```js
chroma('skyblue').hcl()
```
### color.temperature
Estimate the temperature in Kelvin of any given color, though this makes the only sense for colors from the [temperature gradient](#chroma-temperature) above.
```js
chroma('#ff3300').temperature();
chroma('#ff8a13').temperature();
chroma('#ffe3cd').temperature();
chroma('#cbdbff').temperature();
chroma('#b3ccff').temperature();
```
### color.gl
Like RGB, but in the channel range of `[0..1]` instead of `[0..255]`
```js
chroma('33cc00').gl();
```
### color.clipped
When converting colors from CIELab color spaces to RGB the color channels get clipped to the range of `[0..255]`. Colors outside that range may exist in nature but are not displayable on RGB monitors (such as ultraviolet). you can use color.clipped to test if a color has been clipped or not.
```js
[c = chroma.hcl(50, 40, 20), c.clipped()];
[c = chroma.hcl(50, 40, 40), c.clipped()];
[c = chroma.hcl(50, 40, 60), c.clipped()];
[c = chroma.hcl(50, 40, 80), c.clipped()];
[c = chroma.hcl(50, 40, 100), c.clipped()];
```
As a bonus feature you can access the unclipped RGB components using `color._rgb._unclipped`.
```js
chroma.hcl(50, 40, 100).rgb();
chroma.hcl(50, 40, 100)._rgb._unclipped;
```
## color scales
### chroma.scale
#### (colors=['white','black'])
A color scale, created with `chroma.scale`, is a function that maps numeric values to a color palette. The default scale has the domain `0..1` and goes from white to black.
```js
f = chroma.scale();
f(0.25);
f(0.5);
f(0.75);
```
You can pass an array of colors to `chroma.scale`. Any color that can be read by `chroma()` will work here, too. If you pass more than two colors, they will be evenly distributed along the gradient.
```js
chroma.scale(['yellow', '008ae5']);
chroma.scale(['yellow', 'red', 'black']);
```
### scale.domain
#### (domain)
You can change the input domain to match your specific use case.
```js
// default domain is [0,1]
chroma.scale(['yellow', '008ae5']);
// set domain to [0,100]
chroma.scale(['yellow', '008ae5']).domain([0,100]);
```
You can use the domain to set the exact positions of each color.
```js
// default domain is [0,1]
chroma.scale(['yellow', 'lightgreen', '008ae5'])
.domain([0,0.25,1]);
```
### scale.mode
#### (mode)
As with `chroma.mix`, the result of the color interpolation will depend on the color mode in which the channels are interpolated. The default mode is `RGB`:
```js
chroma.scale(['yellow', '008ae5']);
```
This is often fine, but sometimes, two-color `RGB` gradients goes through kind of grayish colors, and `Lab` interpolation produces better results:
```js
chroma.scale(['yellow', 'navy']);
chroma.scale(['yellow', 'navy']).mode('lab');
```
Other useful interpolation modes could be `HSL` or `Lch`, though both tend to produce too saturated / glowing gradients.
```js
chroma.scale(['yellow', 'navy']).mode('lab');
chroma.scale(['yellow', 'navy']).mode('hsl');
chroma.scale(['yellow', 'navy']).mode('lch');
```
### scale.correctLightness
Sometimes
```js
chroma.scale(['yellow', '008ae5']).mode('lch');
chroma.scale(['yellow', '008ae5'])
.mode('lch')
.correctLightness();
```
### scale.cache
#### (true|false)
By default `chroma.scale` instances will cache each computed value => color pair. You can turn off the cache by setting
```js
chroma.scale(['yellow', '008ae5']).cache(false);
```
### scale.padding
#### (pad)
Reduces the color range by cutting of a fraction of the gradient on both sides. If you pass a single number, the same padding will be applied to both ends.
```js
chroma.scale('RdYlBu');
chroma.scale('RdYlBu').padding(0.15);
chroma.scale('RdYlBu').padding(0.3);
chroma.scale('RdYlBu').padding(-0.15);
```
Alternatively you can specify the padding for each sides individually by passing an array of two numbers.
```js
chroma.scale('OrRd');
chroma.scale('OrRd').padding([0.2, 0]);
```
### scale.colors
#### (num, format='hex')
You can call `scale.colors(n)` to quickly grab `n` equi-distant colors from a color scale. If called with no arguments, `scale.colors` returns the original array of colors used to create the scale.
```js
chroma.scale('OrRd').colors(5);
chroma.scale(['white', 'black']).colors(12);
```
### scale.classes
#### (numOrArray)
If you want the scale function to return a distinct set of colors instead of a continuous gradient, you can use `scale.classes`. If you pass a number the scale will broken into equi-distant classes:
```js
// continuous
chroma.scale('OrRd');
// class breaks
chroma.scale('OrRd').classes(5);
chroma.scale('OrRd').classes(8);
```
You can also define custom class breaks by passing them as array:
```js
chroma.scale('OrRd').classes([0,0.3,0.55,0.85,1]);
```
### chroma.brewer
chroma.js includes the definitions from [ColorBrewer2.org](http://colorbrewer2.org/). Read more about these colors [in the corresponding paper](http://www.albany.edu/faculty/fboscoe/papers/harrower2003.pdf) by Mark Harrower and Cynthia A. Brewer.
```js
chroma.scale('YlGnBu');
chroma.scale('Spectral');
```
To reverse the colors you could simply reverse the domain:
```js
chroma.scale('Spectral').domain([1,0]);
```
You can access the colors directly using `chroma.brewer`.
```js
chroma.brewer.OrRd
```
### chroma.bezier
#### (colors)
`chroma.bezier` returns a function that [bezier-interpolates between colors](https://www.vis4.net/blog/posts/mastering-multi-hued-color-scales/) in `Lab` space. The input range of the function is `[0..1]`.
```js
// linear interpolation
chroma.scale(['yellow', 'red', 'black']);
// bezier interpolation
chroma.bezier(['yellow', 'red', 'black']);
```
You can convert an bezier interpolator into a chroma.scale instance
```js
chroma.bezier(['yellow', 'red', 'black'])
.scale()
.colors(5);
```
## cubehelix
### chroma.cubehelix
#### (start=300, rotations=-1.5, hue=1, gamma=1, lightness=[0,1])
Dave Green's [cubehelix color scheme](http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/)!!
```js
// use the default helix...
chroma.cubehelix();
// or customize it
chroma.cubehelix()
.start(200)
.rotations(-0.5)
.gamma(0.8)
.lightness([0.3, 0.8]);
```
### cubehelix.start
#### (hue)
**start** color for [hue rotation](http://en.wikipedia.org/wiki/Hue#/media/File:HueScale.svg), default=`300`
```js
chroma.cubehelix().start(300);
chroma.cubehelix().start(200);
```
### cubehelix.rotations
#### (num)
number (and direction) of hue rotations (e.g. 1=`360°`, 1.5=`540°``), default=-1.5
```js
chroma.cubehelix().rotations(-1.5);
chroma.cubehelix().rotations(0.5);
chroma.cubehelix().rotations(3);
```
### cubehelix.hue
#### (numOrRange)
hue controls how saturated the colour of all hues are. either single value or range, default=1
```js
chroma.cubehelix();
chroma.cubehelix().hue(0.5);
chroma.cubehelix().hue([1,0]);
```
### cubehelix.gamma
#### (factor)
gamma factor can be used to emphasise low or high intensity values, default=1
```js
chroma.cubehelix().gamma(1);
chroma.cubehelix().gamma(0.5);
```
### cubehelix.lightness
#### (range)
lightness range: default: [0,1] (black -> white)
```js
chroma.cubehelix().lightness([0,1]);
chroma.cubehelix().lightness([1,0]);
chroma.cubehelix().lightness([0.3,0.7]);
```
### cubehelix.scale
You can call `cubehelix.scale()` to use the cube-helix through the `chroma.scale` interface.
```js
chroma.cubehelix()
.start(200)
.rotations(-0.35)
.gamma(0.7)
.lightness([0.3, 0.8])
.scale() // convert to chroma.scale
.correctLightness()
.colors(5);
```

33
src/static/node_modules/chroma-js/license.coffee generated vendored Normal file
View file

@ -0,0 +1,33 @@
###*
* @license
*
* chroma.js - JavaScript library for color conversions
*
* Copyright (c) 2011-2017, Gregor Aisch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name Gregor Aisch may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
###

111
src/static/node_modules/chroma-js/package.json generated vendored Normal file
View file

@ -0,0 +1,111 @@
{
"_args": [
[
{
"raw": "chroma-js",
"scope": null,
"escapedName": "chroma-js",
"name": "chroma-js",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"C:\\Box Sync\\pyDataVizDay\\src\\static"
]
],
"_from": "chroma-js@latest",
"_id": "chroma-js@1.3.4",
"_inCache": true,
"_location": "/chroma-js",
"_nodeVersion": "6.10.3",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/chroma-js-1.3.4.tgz_1496084623200_0.6962779217865318"
},
"_npmUser": {
"name": "gka",
"email": "mail@driven-by-data.net"
},
"_npmVersion": "3.10.10",
"_phantomChildren": {},
"_requested": {
"raw": "chroma-js",
"scope": null,
"escapedName": "chroma-js",
"name": "chroma-js",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-1.3.4.tgz",
"_shasum": "93a7c19f287960285cc3fdebb205b8ea1a0f04f9",
"_shrinkwrap": null,
"_spec": "chroma-js",
"_where": "C:\\Box Sync\\pyDataVizDay\\src\\static",
"author": {
"name": "Gregor Aisch"
},
"bugs": {
"url": "https://github.com/gka/chroma.js/issues"
},
"dependencies": {},
"description": "JavaScript library for color conversions",
"devDependencies": {
"catty": "github:gka/catty#coffeescript",
"coffee-script": "1.9.2",
"es6-shim": "^0.18.0",
"grunt": "^0.4.5",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-coffee": "^0.13.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-uglify": "^0.9.1",
"grunt-replace": "^0.9.2",
"minimatch": "^3.0.2",
"uglify-js": "2.x",
"vows": "0.8.x"
},
"directories": {},
"dist": {
"shasum": "93a7c19f287960285cc3fdebb205b8ea1a0f04f9",
"tarball": "https://registry.npmjs.org/chroma-js/-/chroma-js-1.3.4.tgz"
},
"gitHead": "3f74b67e79ac7d7a4499eb938b0b7c6f8715a8f4",
"homepage": "https://github.com/gka/chroma.js",
"keywords": [
"color"
],
"main": "chroma.js",
"maintainers": [
{
"name": "celtra",
"email": "developers@celtra.com"
},
{
"name": "gka",
"email": "mail@driven-by-data.net"
}
],
"name": "chroma-js",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/gka/chroma.js.git"
},
"scripts": {
"build": "grunt",
"test": "./node_modules/vows/bin/vows --dot-matrix"
},
"spm": {
"main": "chroma.js",
"ignore": [
"src",
"doc",
"test"
]
},
"version": "1.3.4"
}

87
src/static/node_modules/chroma-js/readme.md generated vendored Normal file
View file

@ -0,0 +1,87 @@
# Chroma.js
[Chroma.js](https://gka.github.io/chroma.js/) is a tiny JavaScript library (14kB) for all kinds of color conversions and color scales.
[![Build Status](https://travis-ci.org/gka/chroma.js.svg?branch=master)](https://travis-ci.org/gka/chroma.js)
### Usage
Initiate and manipulate colors:
```javascript
chroma('#D4F880').darken().hex(); // #9BC04B
```
Working with color scales is easy, too:
```javascript
scale = chroma.scale(['white', 'red']);
scale(0.5).hex(); // #FF7F7F
```
Lab/Lch interpolation looks better than RGB
```javascript
chroma.scale(['white', 'red']).mode('lab');
```
Custom domains! Quantiles! Color Brewer!!
```javascript
chroma.scale('RdYlBu').domain(myValues, 7, 'quantiles');
```
And why not use logarithmic color scales once in your life?
```javascript
chroma.scale(['lightyellow', 'navy']).domain([1, 100000], 7, 'log');
```
### Like it?
Why not dive into the [interactive documentation](http://gka.github.io/chroma.js/) (there's a [static version](https://github.com/gka/chroma.js/blob/v1.3.1/docs/src/index.md), too). You can download [chroma.min.js](https://raw.github.com/gka/chroma.js/master/chroma.min.js) or use the [hosted version on cdnjs.com](https://cdnjs.com/libraries/chroma-js).
You can use it in node.js, too!
npm install chroma-js
Or you can use it in SASS using [chromatic-sass](https://github.com/bugsnag/chromatic-sass)!
### Build instructions
To compile the coffee-script source files you have to run (might have to ``npm install` first)
grunt
To run the tests simply run
npm test
And to update the documentation (thanks!), just do
npm install --global markdown-to-html http-server
cd docs/
make && make preview
### Similar Libraries / Prior Art
* [Chromatist](https://github.com/jrus/chromatist)
* [GrapeFruit](https://github.com/xav/Grapefruit) (Python)
* [colors.py](https://github.com/mattrobenolt/colors.py) (Python)
* [d3.js](https://github.com/mbostock/d3)
### Author
Chroma.js is written by [Gregor Aisch](http://driven-by-data.net).
### License
Released under [BSD license](http://opensource.org/licenses/BSD-3-Clause).
Versions prior to 0.4 were released under [GPL](http://www.gnu.org/licenses/gpl-3.0).
### Further reading
* [How To Avoid Equidistant HSV Colors](https://vis4.net/blog/posts/avoid-equidistant-hsv-colors/)
* [Mastering Multi-hued Color Scales with Chroma.js](https://vis4.net/blog/posts/mastering-multi-hued-color-scales/)

24
src/static/node_modules/chroma-js/src/analyze.coffee generated vendored Normal file
View file

@ -0,0 +1,24 @@
chroma.analyze = (data) ->
r =
min: Number.MAX_VALUE
max: Number.MAX_VALUE*-1
sum: 0
values: []
count: 0
for val in data
if val? and not isNaN val
r.values.push val
r.sum += val
r.min = val if val < r.min
r.max = val if val > r.max
r.count += 1
r.domain = [r.min, r.max]
r.limits = (mode, num) ->
chroma.limits r, mode, num
r

20
src/static/node_modules/chroma-js/src/api.coffee generated vendored Normal file
View file

@ -0,0 +1,20 @@
chroma = () ->
return arguments[0] if arguments[0] instanceof Color
new Color arguments...
_interpolators = []
# CommonJS module is defined
module.exports = chroma if module? and module.exports?
if typeof define == 'function' and define.amd
define [], () -> chroma
else
root = (exports ? this)
root.chroma = chroma
chroma.version = '@@version'
# exposing raw classes for testing purposes

47
src/static/node_modules/chroma-js/src/color.coffee generated vendored Normal file
View file

@ -0,0 +1,47 @@
# @require utils api
_input = {}
_guess_formats = []
_guess_formats_sorted = false
class Color
constructor: () ->
me = @
args = []
for arg in arguments
args.push arg if arg?
# last argument could be the mode
mode = args[args.length-1]
if _input[mode]?
me._rgb = clip_rgb _input[mode] unpack args[...-1]
else
# sort input type guess by desc priotity
if not _guess_formats_sorted
_guess_formats = _guess_formats.sort (a,b) ->
b.p - a.p
_guess_formats_sorted = true
# guess format
for chk in _guess_formats
mode = chk.test args...
break if mode
if mode
me._rgb = clip_rgb _input[mode] args...
# by now we should have a color
console.warn 'unknown format: '+args if not me._rgb?
me._rgb = [0,0,0] if not me._rgb?
# add alpha
me._rgb.push 1 if me._rgb.length == 3
toString: ->
@hex()
clone: ->
chroma(me._rgb)
chroma._input = _input

View file

@ -0,0 +1,67 @@
###*
ColorBrewer colors for chroma.js
Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The
Pennsylvania State University.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
@preserve
###
chroma.brewer = brewer =
# sequential
OrRd: ['#fff7ec', '#fee8c8', '#fdd49e', '#fdbb84', '#fc8d59', '#ef6548', '#d7301f', '#b30000', '#7f0000']
PuBu: ['#fff7fb', '#ece7f2', '#d0d1e6', '#a6bddb', '#74a9cf', '#3690c0', '#0570b0', '#045a8d', '#023858']
BuPu: ['#f7fcfd', '#e0ecf4', '#bfd3e6', '#9ebcda', '#8c96c6', '#8c6bb1', '#88419d', '#810f7c', '#4d004b']
Oranges: ['#fff5eb', '#fee6ce', '#fdd0a2', '#fdae6b', '#fd8d3c', '#f16913', '#d94801', '#a63603', '#7f2704']
BuGn: ['#f7fcfd', '#e5f5f9', '#ccece6', '#99d8c9', '#66c2a4', '#41ae76', '#238b45', '#006d2c', '#00441b']
YlOrBr: ['#ffffe5', '#fff7bc', '#fee391', '#fec44f', '#fe9929', '#ec7014', '#cc4c02', '#993404', '#662506']
YlGn: ['#ffffe5', '#f7fcb9', '#d9f0a3', '#addd8e', '#78c679', '#41ab5d', '#238443', '#006837', '#004529']
Reds: ['#fff5f0', '#fee0d2', '#fcbba1', '#fc9272', '#fb6a4a', '#ef3b2c', '#cb181d', '#a50f15', '#67000d']
RdPu: ['#fff7f3', '#fde0dd', '#fcc5c0', '#fa9fb5', '#f768a1', '#dd3497', '#ae017e', '#7a0177', '#49006a']
Greens: ['#f7fcf5', '#e5f5e0', '#c7e9c0', '#a1d99b', '#74c476', '#41ab5d', '#238b45', '#006d2c', '#00441b']
YlGnBu: ['#ffffd9', '#edf8b1', '#c7e9b4', '#7fcdbb', '#41b6c4', '#1d91c0', '#225ea8', '#253494', '#081d58']
Purples: ['#fcfbfd', '#efedf5', '#dadaeb', '#bcbddc', '#9e9ac8', '#807dba', '#6a51a3', '#54278f', '#3f007d']
GnBu: ['#f7fcf0', '#e0f3db', '#ccebc5', '#a8ddb5', '#7bccc4', '#4eb3d3', '#2b8cbe', '#0868ac', '#084081']
Greys: ['#ffffff', '#f0f0f0', '#d9d9d9', '#bdbdbd', '#969696', '#737373', '#525252', '#252525', '#000000']
YlOrRd: ['#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c', '#bd0026', '#800026']
PuRd: ['#f7f4f9', '#e7e1ef', '#d4b9da', '#c994c7', '#df65b0', '#e7298a', '#ce1256', '#980043', '#67001f']
Blues: ['#f7fbff', '#deebf7', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#08519c', '#08306b']
PuBuGn: ['#fff7fb', '#ece2f0', '#d0d1e6', '#a6bddb', '#67a9cf', '#3690c0', '#02818a', '#016c59', '#014636']
Viridis: ['#440154', '#482777', '#3f4a8a', '#31678e', '#26838f', '#1f9d8a', '#6cce5a', '#b6de2b', '#fee825']
# diverging
Spectral: ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2']
RdYlGn: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850', '#006837']
RdBu: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061']
PiYG: ['#8e0152', '#c51b7d', '#de77ae', '#f1b6da', '#fde0ef', '#f7f7f7', '#e6f5d0', '#b8e186', '#7fbc41', '#4d9221', '#276419']
PRGn: ['#40004b', '#762a83', '#9970ab', '#c2a5cf', '#e7d4e8', '#f7f7f7', '#d9f0d3', '#a6dba0', '#5aae61', '#1b7837', '#00441b']
RdYlBu: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee090', '#ffffbf', '#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695']
BrBG: ['#543005', '#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e', '#003c30']
RdGy: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#ffffff', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a']
PuOr: ['#7f3b08', '#b35806', '#e08214', '#fdb863', '#fee0b6', '#f7f7f7', '#d8daeb', '#b2abd2', '#8073ac', '#542788', '#2d004b']
# qualitative
Set2: ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3', '#a6d854', '#ffd92f', '#e5c494', '#b3b3b3']
Accent: ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666']
Set1: ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00', '#ffff33', '#a65628', '#f781bf', '#999999']
Set3: ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd', '#ccebc5', '#ffed6f']
Dark2: ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666']
Paired: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928']
Pastel2: ['#b3e2cd', '#fdcdac', '#cbd5e8', '#f4cae4', '#e6f5c9', '#fff2ae', '#f1e2cc', '#cccccc']
Pastel1: ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4', '#fed9a6', '#ffffcc', '#e5d8bd', '#fddaec', '#f2f2f2']
# add lowercase aliases for case-insensitive matches
do -> brewer[key.toLowerCase()] = brewer[key] for key of brewer

View file

@ -0,0 +1,164 @@
###*
X11 color names
http://www.w3.org/TR/css3-color/#svg-color
###
w3cx11 =
aliceblue: '#f0f8ff'
antiquewhite: '#faebd7'
aqua: '#00ffff'
aquamarine: '#7fffd4'
azure: '#f0ffff'
beige: '#f5f5dc'
bisque: '#ffe4c4'
black: '#000000'
blanchedalmond: '#ffebcd'
blue: '#0000ff'
blueviolet: '#8a2be2'
brown: '#a52a2a'
burlywood: '#deb887'
cadetblue: '#5f9ea0'
chartreuse: '#7fff00'
chocolate: '#d2691e'
coral: '#ff7f50'
cornflower: '#6495ed'
cornflowerblue: '#6495ed'
cornsilk: '#fff8dc'
crimson: '#dc143c'
cyan: '#00ffff'
darkblue: '#00008b'
darkcyan: '#008b8b'
darkgoldenrod: '#b8860b'
darkgray: '#a9a9a9'
darkgreen: '#006400'
darkgrey: '#a9a9a9'
darkkhaki: '#bdb76b'
darkmagenta: '#8b008b'
darkolivegreen: '#556b2f'
darkorange: '#ff8c00'
darkorchid: '#9932cc'
darkred: '#8b0000'
darksalmon: '#e9967a'
darkseagreen: '#8fbc8f'
darkslateblue: '#483d8b'
darkslategray: '#2f4f4f'
darkslategrey: '#2f4f4f'
darkturquoise: '#00ced1'
darkviolet: '#9400d3'
deeppink: '#ff1493'
deepskyblue: '#00bfff'
dimgray: '#696969'
dimgrey: '#696969'
dodgerblue: '#1e90ff'
firebrick: '#b22222'
floralwhite: '#fffaf0'
forestgreen: '#228b22'
fuchsia: '#ff00ff'
gainsboro: '#dcdcdc'
ghostwhite: '#f8f8ff'
gold: '#ffd700'
goldenrod: '#daa520'
gray: '#808080'
green: '#008000'
greenyellow: '#adff2f'
grey: '#808080'
honeydew: '#f0fff0'
hotpink: '#ff69b4'
indianred: '#cd5c5c'
indigo: '#4b0082'
ivory: '#fffff0'
khaki: '#f0e68c'
laserlemon: '#ffff54'
lavender: '#e6e6fa'
lavenderblush: '#fff0f5'
lawngreen: '#7cfc00'
lemonchiffon: '#fffacd'
lightblue: '#add8e6'
lightcoral: '#f08080'
lightcyan: '#e0ffff'
lightgoldenrod: '#fafad2'
lightgoldenrodyellow: '#fafad2'
lightgray: '#d3d3d3'
lightgreen: '#90ee90'
lightgrey: '#d3d3d3'
lightpink: '#ffb6c1'
lightsalmon: '#ffa07a'
lightseagreen: '#20b2aa'
lightskyblue: '#87cefa'
lightslategray: '#778899'
lightslategrey: '#778899'
lightsteelblue: '#b0c4de'
lightyellow: '#ffffe0'
lime: '#00ff00'
limegreen: '#32cd32'
linen: '#faf0e6'
magenta: '#ff00ff'
maroon: '#800000'
maroon2: '#7f0000'
maroon3: '#b03060'
mediumaquamarine: '#66cdaa'
mediumblue: '#0000cd'
mediumorchid: '#ba55d3'
mediumpurple: '#9370db'
mediumseagreen: '#3cb371'
mediumslateblue: '#7b68ee'
mediumspringgreen: '#00fa9a'
mediumturquoise: '#48d1cc'
mediumvioletred: '#c71585'
midnightblue: '#191970'
mintcream: '#f5fffa'
mistyrose: '#ffe4e1'
moccasin: '#ffe4b5'
navajowhite: '#ffdead'
navy: '#000080'
oldlace: '#fdf5e6'
olive: '#808000'
olivedrab: '#6b8e23'
orange: '#ffa500'
orangered: '#ff4500'
orchid: '#da70d6'
palegoldenrod: '#eee8aa'
palegreen: '#98fb98'
paleturquoise: '#afeeee'
palevioletred: '#db7093'
papayawhip: '#ffefd5'
peachpuff: '#ffdab9'
peru: '#cd853f'
pink: '#ffc0cb'
plum: '#dda0dd'
powderblue: '#b0e0e6'
purple: '#800080'
purple2: '#7f007f'
purple3: '#a020f0'
rebeccapurple: '#663399'
red: '#ff0000'
rosybrown: '#bc8f8f'
royalblue: '#4169e1'
saddlebrown: '#8b4513'
salmon: '#fa8072'
sandybrown: '#f4a460'
seagreen: '#2e8b57'
seashell: '#fff5ee'
sienna: '#a0522d'
silver: '#c0c0c0'
skyblue: '#87ceeb'
slateblue: '#6a5acd'
slategray: '#708090'
slategrey: '#708090'
snow: '#fffafa'
springgreen: '#00ff7f'
steelblue: '#4682b4'
tan: '#d2b48c'
teal: '#008080'
thistle: '#d8bfd8'
tomato: '#ff6347'
turquoise: '#40e0d0'
violet: '#ee82ee'
wheat: '#f5deb3'
white: '#ffffff'
whitesmoke: '#f5f5f5'
yellow: '#ffff00'
yellowgreen: '#9acd32'
chroma.colors = colors = w3cx11

View file

@ -0,0 +1,10 @@
cmyk2rgb = () ->
args = unpack arguments
[c,m,y,k] = args
alpha = if args.length > 4 then args[4] else 1
return [0,0,0,alpha] if k == 1
r = if c >= 1 then 0 else 255 * (1-c) * (1-k)
g = if m >= 1 then 0 else 255 * (1-m) * (1-k)
b = if y >= 1 then 0 else 255 * (1-y) * (1-k)
[r,g,b,alpha]

View file

@ -0,0 +1,45 @@
# @requires utils hex2rgb hsl2rgb
css2rgb = (css) ->
css = css.toLowerCase()
# named X11 colors
if chroma.colors? and chroma.colors[css]
return hex2rgb chroma.colors[css]
# rgb(250,20,0)
if m = css.match /rgb\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)/
rgb = m.slice 1,4
for i in [0..2]
rgb[i] = +rgb[i]
rgb[3] = 1 # default alpha
# rgba(250,20,0,0.4)
else if m = css.match /rgba\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*,\s*([01]|[01]?\.\d+)\)/
rgb = m.slice 1,5
for i in [0..3]
rgb[i] = +rgb[i]
# rgb(100%,0%,0%)
else if m = css.match /rgb\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/
rgb = m.slice 1,4
for i in [0..2]
rgb[i] = round rgb[i] * 2.55
rgb[3] = 1 # default alpha
# rgba(100%,0%,0%,0.4)
else if m = css.match /rgba\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/
rgb = m.slice 1,5
for i in [0..2]
rgb[i] = round rgb[i] * 2.55
rgb[3] = +rgb[3]
# hsl(0,100%,50%)
else if m = css.match /hsl\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/
hsl = m.slice 1,4
hsl[1] *= 0.01
hsl[2] *= 0.01
rgb = hsl2rgb hsl
rgb[3] = 1
# hsla(0,100%,50%,0.5)
else if m = css.match /hsla\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/
hsl = m.slice 1,4
hsl[1] *= 0.01
hsl[2] *= 0.01
rgb = hsl2rgb hsl
rgb[3] = +m[4] # default alpha = 1
rgb

View file

@ -0,0 +1,28 @@
hcg2rgb = () ->
args = unpack arguments
[h,c,_g] = args
c = c / 100
g = g / 100 * 255
_c = c * 255
if c is 0
r = g = b = _g
else
h = 0 if h is 360
h -= 360 if h > 360
h += 360 if h < 0
h /= 60
i = floor h
f = h - i
p = _g * (1 - c)
q = p + _c * (1 - f)
t = p + _c * f
v = p + _c
switch i
when 0 then [r,g,b] = [v, t, p]
when 1 then [r,g,b] = [q, v, p]
when 2 then [r,g,b] = [p, v, t]
when 3 then [r,g,b] = [p, q, v]
when 4 then [r,g,b] = [t, p, v]
when 5 then [r,g,b] = [v, p, q]
[r, g, b, if args.length > 3 then args[3] else 1]

View file

@ -0,0 +1,29 @@
hex2rgb = (hex) ->
if hex.match /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
if hex.length == 4 or hex.length == 7
hex = hex.substr(1)
if hex.length == 3
hex = hex.split("")
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]
u = parseInt(hex, 16)
r = u >> 16
g = u >> 8 & 0xFF
b = u & 0xFF
return [r,g,b,1]
# match rgba hex format, eg #FF000077
if hex.match /^#?([A-Fa-f0-9]{8})$/
if hex.length == 9
hex = hex.substr(1)
u = parseInt(hex, 16)
r = u >> 24 & 0xFF
g = u >> 16 & 0xFF
b = u >> 8 & 0xFF
a = round((u & 0xFF) / 0xFF * 100) / 100
return [r,g,b,a]
# check for css colors, too
if _input.css? and rgb = _input.css hex
return rgb
throw "unknown color: "+hex

View file

@ -0,0 +1,33 @@
# @requires utils
hsi2rgb = (h,s,i) ->
###
borrowed from here:
http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/hsi2rgb.cpp
###
args = unpack arguments
[h,s,i] = args
# normalize hue
#h += 360 if h < 0
#h -= 360 if h > 360
h = 0 if isNaN h
h /= 360
if h < 1/3
b = (1-s)/3
r = (1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3
g = 1 - (b+r)
else if h < 2/3
h -= 1/3
r = (1-s)/3
g = (1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3
b = 1 - (r+g)
else
h -= 2/3
g = (1-s)/3
b = (1+s*cos(TWOPI*h)/cos(PITHIRD-TWOPI*h))/3
r = 1 - (g+b)
r = limit i*r*3
g = limit i*g*3
b = limit i*b*3
[r*255, g*255, b*255, if args.length > 3 then args[3] else 1]

View file

@ -0,0 +1,29 @@
# @requires utils
hsl2rgb = () ->
args = unpack arguments
[h,s,l] = args
if s == 0
r = g = b = l*255
else
t3 = [0,0,0]
c = [0,0,0]
t2 = if l < 0.5 then l * (1+s) else l+s-l*s
t1 = 2 * l - t2
h /= 360
t3[0] = h + 1/3
t3[1] = h
t3[2] = h - 1/3
for i in [0..2]
t3[i] += 1 if t3[i] < 0
t3[i] -= 1 if t3[i] > 1
if 6 * t3[i] < 1
c[i] = t1 + (t2 - t1) * 6 * t3[i]
else if 2 * t3[i] < 1
c[i] = t2
else if 3 * t3[i] < 2
c[i] = t1 + (t2 - t1) * ((2 / 3) - t3[i]) * 6
else
c[i] = t1
[r,g,b] = [round(c[0]*255),round(c[1]*255),round(c[2]*255)]
if args.length > 3 then [r,g,b,args[3]] else [r,g,b]

View file

@ -0,0 +1,25 @@
hsv2rgb = () ->
args = unpack arguments
[h,s,v] = args
v *= 255
if s is 0
r = g = b = v
else
h = 0 if h is 360
h -= 360 if h > 360
h += 360 if h < 0
h /= 60
i = floor h
f = h - i
p = v * (1 - s)
q = v * (1 - s * f)
t = v * (1 - s * (1 - f))
switch i
when 0 then [r,g,b] = [v, t, p]
when 1 then [r,g,b] = [q, v, p]
when 2 then [r,g,b] = [p, v, t]
when 3 then [r,g,b] = [p, q, v]
when 4 then [r,g,b] = [t, p, v]
when 5 then [r,g,b] = [v, p, q]
[r, g, b, if args.length > 3 then args[3] else 1]

View file

@ -0,0 +1,27 @@
# requires lab-constants
lab2rgb = () ->
args = unpack arguments
[l,a,b] = args
y = (l + 16) / 116
x = if isNaN(a) then y else y + a / 500
z = if isNaN(b) then y else y - b / 200
y = LAB_CONSTANTS.Yn * lab_xyz y
x = LAB_CONSTANTS.Xn * lab_xyz x
z = LAB_CONSTANTS.Zn * lab_xyz z
r = xyz_rgb 3.2404542 * x - 1.5371385 * y - 0.4985314 * z # D65 -> sRGB
g = xyz_rgb -0.9692660 * x + 1.8760108 * y + 0.0415560 * z
b = xyz_rgb 0.0556434 * x - 0.2040259 * y + 1.0572252 * z
[r,g,b,if args.length > 3 then args[3] else 1]
xyz_rgb = (r) ->
255 * (if r <= 0.00304 then 12.92 * r else 1.055 * pow(r, 1 / 2.4) - 0.055)
lab_xyz = (t) ->
if t > LAB_CONSTANTS.t1 then t * t * t else LAB_CONSTANTS.t2 * (t - LAB_CONSTANTS.t0)

View file

@ -0,0 +1,8 @@
# @requires utils lch2lab
lch2rgb = () ->
args = unpack arguments
[l,c,h] = args
[L,a,b] = lch2lab l,c,h
[r,g,b] = lab2rgb L,a,b
[r, g, b, if args.length > 3 then args[3] else 1]

View file

@ -0,0 +1,10 @@
# @requires utils
num2rgb = (num) ->
if type(num) == "number" && num >= 0 && num <= 0xFFFFFF
r = num >> 16
g = (num >> 8) & 0xFF
b = num & 0xFF
return [r,g,b,1]
console.warn "unknown num color: "+num
[0,0,0,1]

View file

@ -0,0 +1,18 @@
#
# Based on implementation by Neil Bartlett
# https://github.com/neilbartlett/color-temperature
#
# @requires utils
temperature2rgb = (kelvin) ->
temp = kelvin / 100
if temp < 66
r = 255
g = -155.25485562709179 - 0.44596950469579133 * (g = temp-2) + 104.49216199393888 * log(g)
b = if temp < 20 then 0 else -254.76935184120902 + 0.8274096064007395 * (b = temp-10) + 115.67994401066147 * log(b)
else
r = 351.97690566805693 + 0.114206453784165 * (r = temp-55) - 40.25366309332127 * log(r)
g = 325.4494125711974 + 0.07943456536662342 * (g = temp-50) - 28.0852963507957 * log(g)
b = 255
[r,g,b]

View file

@ -0,0 +1,16 @@
LAB_CONSTANTS =
# Corresponds roughly to RGB brighter/darker
Kn: 18
# D65 standard referent
Xn: 0.950470
Yn: 1
Zn: 1.088830
t0: 0.137931034 # 4 / 29
t1: 0.206896552 # 6 / 29
t2: 0.12841855 # 3 * t1 * t1
t3: 0.008856452 # t1 * t1 * t1

View file

@ -0,0 +1,8 @@
# @requires utils
lab2lch = () ->
[l, a, b] = unpack arguments
c = sqrt(a * a + b * b)
h = (atan2(b, a) * RAD2DEG + 360) % 360
h = Number.NaN if round(c*10000) == 0
[l, c, h]

View file

@ -0,0 +1,13 @@
# @requires utils
lch2lab = () ->
###
Convert from a qualitative parameter h and a quantitative parameter l to a 24-bit pixel.
These formulas were invented by David Dalrymple to obtain maximum contrast without going
out of gamut if the parameters are in the range 0-1.
A saturation multiplier was added by Gregor Aisch
###
[l,c,h] = unpack arguments
h = h * DEG2RAD
[l, cos(h) * c, sin(h) * c]

View file

@ -0,0 +1,11 @@
# @requires utils
rnd = (a) -> round(a*100)/100
hsl2css = (hsl, alpha) ->
mode = if alpha < 1 then 'hsla' else 'hsl'
hsl[0] = rnd(hsl[0] || 0)
hsl[1] = rnd(hsl[1]*100) + '%'
hsl[2] = rnd(hsl[2]*100) + '%'
hsl[3] = alpha if mode == 'hsla'
mode + '(' + hsl.join(',') + ')'

View file

@ -0,0 +1,12 @@
rgb2cmyk = (mode='rgb') ->
[r,g,b] = unpack arguments
r = r / 255
g = g / 255
b = b / 255
k = 1 - Math.max(r,Math.max(g,b))
f = if k < 1 then 1 / (1-k) else 0
c = (1-r-k) * f
m = (1-g-k) * f
y = (1-b-k) * f
[c,m,y,k]

View file

@ -0,0 +1,10 @@
# @requires utils
rgb2css = (rgba) ->
mode = if rgba[3] < 1 then 'rgba' else 'rgb'
if mode == 'rgb'
mode+'('+rgba.slice(0,3).map(round).join(',')+')'
else if mode == 'rgba'
mode+'('+rgba.slice(0,3).map(round).join(',')+','+rgba[3]+')'
else

View file

@ -0,0 +1,17 @@
rgb2hcg = () ->
[r,g,b] = unpack arguments
min = Math.min(r, g, b)
max = Math.max(r, g, b)
delta = max - min
c = delta * 100 / 255
_g = min / (255 - delta) * 100
if delta == 0
h = Number.NaN
else
if r is max then h = (g - b) / delta
if g is max then h = 2+(b - r) / delta
if b is max then h = 4+(r - g) / delta
h *= 60
if h < 0 then h += 360
[h, c, _g]

View file

@ -0,0 +1,15 @@
rgb2hex = (channels, mode='rgb') ->
[r,g,b,a] = channels
r = Math.round r
g = Math.round g
b = Math.round b
u = r << 16 | g << 8 | b
str = "000000" + u.toString(16) #.toUpperCase()
str = str.substr(str.length - 6)
hxa = '0' + round(a * 255).toString(16)
hxa = hxa.substr(hxa.length - 2)
"#" + switch mode.toLowerCase()
when 'rgba' then str + hxa
when 'argb' then hxa + str
else str

View file

@ -0,0 +1,26 @@
# @requires utils
rgb2hsi = () ->
###
borrowed from here:
http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/rgb2hsi.cpp
###
[r,g,b] = unpack arguments
TWOPI = Math.PI*2
r /= 255
g /= 255
b /= 255
min = Math.min(r,g,b)
i = (r+g+b) / 3
s = 1 - min/i
if s == 0
h = 0
else
h = ((r-g)+(r-b)) / 2
h /= Math.sqrt((r-g)*(r-g) + (r-b)*(g-b))
h = Math.acos(h)
if b > g
h = TWOPI - h
h /= TWOPI
[h*360,s,i]

View file

@ -0,0 +1,26 @@
rgb2hsl = (r,g,b) ->
if r != undefined and r.length >= 3
[r,g,b] = r
r /= 255
g /= 255
b /= 255
min = Math.min(r, g, b)
max = Math.max(r, g, b)
l = (max + min) / 2
if max == min
s = 0
h = Number.NaN
else
s = if l < 0.5 then (max - min) / (max + min) else (max - min) / (2 - max - min)
if r == max then h = (g - b) / (max - min)
else if (g == max) then h = 2 + (b - r) / (max - min)
else if (b == max) then h = 4 + (r - g) / (max - min)
h *= 60;
h += 360 if h < 0
[h,s,l]

View file

@ -0,0 +1,18 @@
rgb2hsv = () ->
[r,g,b] = unpack arguments
min = Math.min(r, g, b)
max = Math.max(r, g, b)
delta = max - min
v = max / 255.0
if max == 0
h = Number.NaN
s = 0
else
s = delta / max
if r is max then h = (g - b) / delta
if g is max then h = 2+(b - r) / delta
if b is max then h = 4+(r - g) / delta
h *= 60;
if h < 0 then h += 360
[h, s, v]

View file

@ -0,0 +1,22 @@
# @requires utils lab-constants
rgb2lab = () ->
[r,g,b] = unpack arguments
[x,y,z] = rgb2xyz r,g,b
[116 * y - 16, 500 * (x - y), 200 * (y - z)]
rgb_xyz = (r) ->
if (r /= 255) <= 0.04045 then r / 12.92 else pow((r + 0.055) / 1.055, 2.4)
xyz_lab = (t) ->
if t > LAB_CONSTANTS.t3 then pow(t, 1 / 3) else t / LAB_CONSTANTS.t2 + LAB_CONSTANTS.t0
rgb2xyz = () ->
[r,g,b] = unpack arguments
r = rgb_xyz r
g = rgb_xyz g
b = rgb_xyz b
x = xyz_lab (0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / LAB_CONSTANTS.Xn
y = xyz_lab (0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / LAB_CONSTANTS.Yn
z = xyz_lab (0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / LAB_CONSTANTS.Zn
[x,y,z]

View file

@ -0,0 +1,6 @@
# @requires rgb2lab lab2lch
rgb2lch = () ->
[r,g,b] = unpack arguments
[l,a,b] = rgb2lab r,g,b
lab2lch l,a,b

View file

@ -0,0 +1,16 @@
# @requires utils
rgb2luminance = (r,g,b) ->
# relative luminance
# see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
[r,g,b] = unpack arguments
r = luminance_x r
g = luminance_x g
b = luminance_x b
0.2126 * r + 0.7152 * g + 0.0722 * b
luminance_x = (x) ->
x /= 255
if x <= 0.03928 then x/12.92 else pow((x+0.055)/1.055, 2.4)

View file

@ -0,0 +1,4 @@
rgb2num = () ->
[r,g,b] = unpack arguments
(r << 16) + (g << 8) + b

View file

@ -0,0 +1,20 @@
#
# Based on implementation by Neil Bartlett
# https://github.com/neilbartlett/color-temperature
#
# @requires utils temperature2rgb
rgb2temperature = () ->
[r,g,b] = unpack arguments
minTemp = 1000
maxTemp = 40000
eps = 0.4
while maxTemp - minTemp > eps
temp = (maxTemp + minTemp) * 0.5
rgb = temperature2rgb temp
if (rgb[2] / rgb[0]) >= (b / r)
maxTemp = temp
else
minTemp = temp
round temp

View file

@ -0,0 +1,38 @@
chroma.average = (colors, mode='rgb') ->
l = colors.length
colors = colors.map (c) -> chroma(c)
first = colors.splice(0,1)[0]
xyz = first.get(mode)
cnt = []
dx = 0
dy = 0
for i of xyz
xyz[i] = xyz[i] or 0
cnt.push if not isNaN(xyz[i]) then 1 else 0
if mode.charAt(i) == 'h' and not isNaN(xyz[i])
A = xyz[i] / 180 * PI
dx += cos(A)
dy += sin(A)
alpha = first.alpha()
for c in colors
xyz2 = c.get(mode)
alpha += c.alpha()
for i of xyz
if not isNaN xyz2[i]
xyz[i] += xyz2[i]
cnt[i] += 1
if mode.charAt(i) == 'h'
A = xyz[i] / 180 * PI
dx += cos(A)
dy += sin(A)
for i of xyz
xyz[i] = xyz[i]/cnt[i]
if mode.charAt(i) == 'h'
A = atan2(dy / cnt[i], dx / cnt[i]) / PI * 180
A += 360 while A < 0
A -= 360 while A >= 360
xyz[i] = A
chroma(xyz, mode).alpha(alpha/l)

View file

@ -0,0 +1,43 @@
#
# interpolates between a set of colors uzing a bezier spline
#
# @requires utils lab
bezier = (colors) ->
colors = (chroma(c) for c in colors)
if colors.length == 2
# linear interpolation
[lab0, lab1] = (c.lab() for c in colors)
I = (t) ->
lab = (lab0[i] + t * (lab1[i] - lab0[i]) for i in [0..2])
chroma.lab lab...
else if colors.length == 3
# quadratic bezier interpolation
[lab0, lab1, lab2] = (c.lab() for c in colors)
I = (t) ->
lab = ((1-t)*(1-t) * lab0[i] + 2 * (1-t) * t * lab1[i] + t * t * lab2[i] for i in [0..2])
chroma.lab lab...
else if colors.length == 4
# cubic bezier interpolation
[lab0, lab1, lab2, lab3] = (c.lab() for c in colors)
I = (t) ->
lab = ((1-t)*(1-t)*(1-t) * lab0[i] + 3 * (1-t) * (1-t) * t * lab1[i] + 3 * (1-t) * t * t * lab2[i] + t*t*t * lab3[i] for i in [0..2])
chroma.lab lab...
else if colors.length == 5
I0 = bezier colors[0..2]
I1 = bezier colors[2..4]
I = (t) ->
if t < 0.5
I0 t*2
else
I1 (t-0.5)*2
I
chroma.bezier = (colors) ->
f = bezier colors
f.scale = () ->
chroma.scale f
f

View file

@ -0,0 +1,98 @@
###
chroma.js
Copyright (c) 2011-2013, Gregor Aisch
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name Gregor Aisch may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@source: https://github.com/gka/chroma.js
###
# cubehelix interpolation
# based on D.A. Green "A colour scheme for the display of astronomical intensity images"
# http://astron-soc.in/bulletin/11June/289392011.pdf
chroma.cubehelix = (start=300, rotations=-1.5, hue=1, gamma=1, lightness=[0,1]) ->
dh = 0
if type(lightness) == 'array'
dl = lightness[1] - lightness[0]
else
dl = 0
lightness = [lightness, lightness]
f = (fract) ->
a = TWOPI * ((start+120)/360 + rotations * fract)
l = pow(lightness[0] + dl * fract, gamma)
h = if dh != 0 then hue[0] + fract * dh else hue
amp = h * l * (1-l) / 2
cos_a = cos a
sin_a = sin a
r = l + amp * (-0.14861 * cos_a + 1.78277* sin_a)
g = l + amp * (-0.29227 * cos_a - 0.90649* sin_a)
b = l + amp * (+1.97294 * cos_a)
chroma clip_rgb [r*255,g*255,b*255]
f.start = (s) ->
if not s? then return start
start = s
f
f.rotations = (r) ->
if not r? then return rotations
rotations = r
f
f.gamma = (g) ->
if not g? then return gamma
gamma = g
f
f.hue = (h) ->
if not h? then return hue
hue = h
if type(hue) == 'array'
dh = hue[1] - hue[0]
hue = hue[1] if dh == 0
else
dh = 0
f
f.lightness = (h) ->
if not h? then return lightness
if type(h) == 'array'
lightness = h
dl = h[1] - h[0]
else
lightness = [h,h]
dl = 0
f
f.scale = () ->
chroma.scale f
f.hue hue
f

View file

@ -0,0 +1,7 @@
chroma.random = ->
digits = '0123456789abcdef'
code = '#'
code += digits.charAt(floor(Math.random() * 16)) for i in [0...6]
new Color code

38
src/static/node_modules/chroma-js/src/index.coffee generated vendored Normal file
View file

@ -0,0 +1,38 @@
###
@requires
color
colorbrewer
w3cx11
bezier
cubehelix
random
average
rgb hex hsl hsv num hcg
css named
lch lab
cmyk
gl
luminance
temperature
contrast
distance
delta-e
get set
clipped
alpha darken saturate premultiply blend
scale
limits
interpolate-hsx
interpolate-rgb
interpolate-num
interpolate-lab
###

View file

@ -0,0 +1,47 @@
# @requires interpolate hsl hsv hsi lch hcg
interpolate_hsx = (col1, col2, f, m) ->
if m == 'hsl'
xyz0 = col1.hsl()
xyz1 = col2.hsl()
else if m == 'hsv'
xyz0 = col1.hsv()
xyz1 = col2.hsv()
else if m == 'hcg'
xyz0 = col1.hcg()
xyz1 = col2.hcg()
else if m == 'hsi'
xyz0 = col1.hsi()
xyz1 = col2.hsi()
else if m == 'lch' or m == 'hcl'
m = 'hcl'
xyz0 = col1.hcl()
xyz1 = col2.hcl()
if m.substr(0, 1) == 'h'
[hue0, sat0, lbv0] = xyz0
[hue1, sat1, lbv1] = xyz1
if not isNaN(hue0) and not isNaN(hue1)
if hue1 > hue0 and hue1 - hue0 > 180
dh = hue1-(hue0+360)
else if hue1 < hue0 and hue0 - hue1 > 180
dh = hue1+360-hue0
else
dh = hue1 - hue0
hue = hue0+f*dh
else if not isNaN(hue0)
hue = hue0
sat = sat0 if (lbv1 == 1 or lbv1 == 0) and m != 'hsv'
else if not isNaN(hue1)
hue = hue1
sat = sat1 if (lbv0 == 1 or lbv0 == 0) and m != 'hsv'
else
hue = Number.NaN
sat ?= sat0 + f*(sat1 - sat0)
lbv = lbv0 + f*(lbv1-lbv0)
res = chroma[m](hue, sat, lbv)
_interpolators = _interpolators.concat ([m, interpolate_hsx] for m in ['hsv','hsl','hsi','hcl','lch','hcg'])

View file

@ -0,0 +1,13 @@
# @requires interpolate lab
interpolate_lab = (col1, col2, f, m) ->
xyz0 = col1.lab()
xyz1 = col2.lab()
res = new Color(
xyz0[0] + f * (xyz1[0]-xyz0[0]),
xyz0[1] + f * (xyz1[1]-xyz0[1]),
xyz0[2] + f * (xyz1[2]-xyz0[2]),
m
)
_interpolators.push ['lab', interpolate_lab]

View file

@ -0,0 +1,8 @@
# @requires interpolate num
interpolate_num = (col1, col2, f, m) ->
n1 = col1.num()
n2 = col2.num()
chroma.num n1 + (n2-n1) * f, 'num'
_interpolators.push ['num', interpolate_num]

View file

@ -0,0 +1,13 @@
# @requires interpolate rgb
interpolate_rgb = (col1, col2, f, m) ->
xyz0 = col1._rgb
xyz1 = col2._rgb
new Color(
xyz0[0] + f * (xyz1[0]-xyz0[0]),
xyz0[1] + f * (xyz1[1]-xyz0[1]),
xyz0[2] + f * (xyz1[2]-xyz0[2]),
m
)
_interpolators.push ['rgb', interpolate_rgb]

View file

@ -0,0 +1,34 @@
###
@requires
color
utils
###
_interpolators = []
interpolate = (col1, col2, f=0.5, m='rgb') ->
###
interpolates between colors
f = 0 --> me
f = 1 --> col
###
col1 = chroma col1 if type(col1) != 'object'
col2 = chroma col2 if type(col2) != 'object'
for interpol in _interpolators
if m == interpol[0]
res = interpol[1] col1, col2, f, m
break
throw "color mode "+m+" is not supported" if not res?
# interpolate alpha at last
return res.alpha col1.alpha() + f * (col2.alpha() - col1.alpha())
chroma.interpolate = interpolate
Color::interpolate = (col2, f, m) ->
interpolate @, col2, f, m
chroma.mix = interpolate
Color::mix = Color::interpolate

11
src/static/node_modules/chroma-js/src/io/cmyk.coffee generated vendored Normal file
View file

@ -0,0 +1,11 @@
# @require utils rgb2cmyk cmyk2rgb
_input.cmyk = () ->
cmyk2rgb unpack arguments
chroma.cmyk = () ->
new Color arguments..., 'cmyk'
Color::cmyk = () ->
rgb2cmyk @_rgb

View file

@ -0,0 +1,9 @@
chroma.contrast = (a, b) ->
# WCAG contrast ratio
# see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
a = new Color a if type(a) in ['string', 'number']
b = new Color b if type(b) in ['string', 'number']
l1 = a.luminance()
l2 = b.luminance()
if l1 > l2 then (l1 + 0.05) / (l2 + 0.05) else (l2 + 0.05) / (l1 + 0.05)

13
src/static/node_modules/chroma-js/src/io/css.coffee generated vendored Normal file
View file

@ -0,0 +1,13 @@
# @requires utils css2rgb rgb2css hsl2css
_input.css = (h) ->
css2rgb h
chroma.css = () ->
new Color arguments..., 'css'
Color::css = (mode='rgb') ->
if mode[0..2] == 'rgb'
rgb2css @_rgb
else if mode[0..2] == 'hsl'
hsl2css @hsl(), @alpha()

View file

@ -0,0 +1,29 @@
chroma.deltaE = (a, b, L=1, C=1) ->
# Delta E (CMC)
# see http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CMC.html
a = new Color a if type(a) in ['string', 'number']
b = new Color b if type(b) in ['string', 'number']
[L1,a1,b1] = a.lab()
[L2,a2,b2] = b.lab()
c1 = sqrt(a1 * a1 + b1 * b1)
c2 = sqrt(a2 * a2 + b2 * b2)
sl = if L1 < 16.0 then 0.511 else (0.040975 * L1) / (1.0 + 0.01765 * L1)
sc = (0.0638 * c1) / (1.0 + 0.0131 * c1) + 0.638
h1 = if c1 < 0.000001 then 0.0 else (atan2(b1, a1) * 180.0) / PI
h1 += 360 while h1 < 0
h1 -= 360 while h1 >= 360
t = if (h1 >= 164.0) && (h1 <= 345.0) then (0.56 + abs(0.2 * cos((PI * (h1 + 168.0)) / 180.0))) else (0.36 + abs(0.4 * cos((PI * (h1 + 35.0)) / 180.0)))
c4 = c1 * c1 * c1 * c1
f = sqrt(c4 / (c4 + 1900.0))
sh = sc * (f * t + 1.0 - f)
delL = L1 - L2
delC = c1 - c2
delA = a1 - a2
delB = b1 - b2
dH2 = delA * delA + delB * delB - delC * delC
v1 = delL / (L * sl)
v2 = delC / (C * sc)
v3 = sh
sqrt(v1 * v1 + v2 * v2 + (dH2 / (v3 * v3)))

View file

@ -0,0 +1,13 @@
# simple eucledian distance
chroma.distance = (a, b, mode='lab') ->
# Delta E (CIE 1976)
# see http://www.brucelindbloom.com/index.html?Equations.html
a = new Color a if type(a) in ['string', 'number']
b = new Color b if type(b) in ['string', 'number']
l1 = a.get mode
l2 = b.get mode
sum_sq = 0
for i of l1
d = (l1[i] || 0) - (l2[i] || 0)
sum_sq += d*d
Math.sqrt sum_sq

14
src/static/node_modules/chroma-js/src/io/gl.coffee generated vendored Normal file
View file

@ -0,0 +1,14 @@
# @require utils
_input.gl = () ->
rgb = (v for k,v of unpack arguments)
for i in [0..2]
rgb[i] *= 255
rgb
chroma.gl = () ->
new Color arguments..., 'gl'
Color::gl = () ->
rgb = @_rgb
[rgb[0]/255, rgb[1]/255, rgb[2]/255, rgb[3]]

9
src/static/node_modules/chroma-js/src/io/hcg.coffee generated vendored Normal file
View file

@ -0,0 +1,9 @@
# @require utils hcg2rgb rgb2hcg
chroma.hcg = () ->
new Color arguments..., 'hcg'
_input.hcg = hcg2rgb
Color::hcg = () ->
rgb2hcg @_rgb

15
src/static/node_modules/chroma-js/src/io/hex.coffee generated vendored Normal file
View file

@ -0,0 +1,15 @@
# @require hex2rgb rgb2hex
_input.hex = (h) ->
hex2rgb h
chroma.hex = () ->
new Color arguments..., 'hex'
Color::hex = (mode='rgb') ->
rgb2hex @_rgb, mode
_guess_formats.push
p: 4,
test: (n) ->
'hex' if arguments.length == 1 and type(n) == "string"

11
src/static/node_modules/chroma-js/src/io/hsi.coffee generated vendored Normal file
View file

@ -0,0 +1,11 @@
# @require utils hsi2rgb rgb2hsi
chroma.hsi = () ->
new Color arguments..., 'hsi'
_input.hsi = hsi2rgb
Color::hsi = () ->
rgb2hsi @_rgb

11
src/static/node_modules/chroma-js/src/io/hsl.coffee generated vendored Normal file
View file

@ -0,0 +1,11 @@
# @require utils hsl2rgb rgb2hsl
chroma.hsl = () ->
new Color arguments..., 'hsl'
_input.hsl = hsl2rgb
Color::hsl = () ->
rgb2hsl @_rgb

9
src/static/node_modules/chroma-js/src/io/hsv.coffee generated vendored Normal file
View file

@ -0,0 +1,9 @@
# @require utils hsv2rgb rgb2hsv
chroma.hsv = () ->
new Color arguments..., 'hsv'
_input.hsv = hsv2rgb
Color::hsv = () ->
rgb2hsv @_rgb

11
src/static/node_modules/chroma-js/src/io/lab.coffee generated vendored Normal file
View file

@ -0,0 +1,11 @@
# @require utils lab2rgb rgb2lab
chroma.lab = () ->
new Color arguments..., 'lab'
_input.lab = lab2rgb
Color::lab = () ->
rgb2lab @_rgb

23
src/static/node_modules/chroma-js/src/io/lch.coffee generated vendored Normal file
View file

@ -0,0 +1,23 @@
# @require utils lch2rgb rgb2lch
chroma.lch = () ->
args = unpack arguments
new Color args, 'lch'
chroma.hcl = () ->
args = unpack arguments
new Color args, 'hcl'
_input.lch = lch2rgb
_input.hcl = () ->
[h,c,l] = unpack arguments
lch2rgb [l,c,h]
Color::lch = () ->
rgb2lch @_rgb
Color::hcl = () ->
rgb2lch(@_rgb).reverse()

View file

@ -0,0 +1,23 @@
# @requires rgb2luminance interpolate-rgb
Color::luminance = (lum, mode='rgb') ->
return rgb2luminance @_rgb if !arguments.length
# set luminance
if lum == 0 then @_rgb = [0,0,0,@_rgb[3]]
else if lum == 1 then @_rgb = [255,255,255,@_rgb[3]]
else
eps = 1e-7
max_iter = 20
test = (l,h) ->
m = l.interpolate(h, 0.5, mode)
lm = m.luminance()
if Math.abs(lum - lm) < eps or not max_iter--
return m
if lm > lum
return test(l, m)
return test(m, h)
cur_lum = rgb2luminance @_rgb
@_rgb = (if cur_lum > lum then test(chroma('black'), @) else test(@, chroma('white'))).rgba()
@

23
src/static/node_modules/chroma-js/src/io/named.coffee generated vendored Normal file
View file

@ -0,0 +1,23 @@
#
# @requires hex hex2rgb w3cx11
#
_input.named = (name) ->
hex2rgb w3cx11[name]
_guess_formats.push
p: 5,
test: (n) ->
'named' if arguments.length == 1 and w3cx11[n]?
Color::name = (n) ->
if arguments.length
@_rgb = hex2rgb w3cx11[n] if w3cx11[n]
@_rgb[3] = 1
@
# resolve name from hex
h = @hex()
for k of w3cx11
if h == w3cx11[k]
return k
h

14
src/static/node_modules/chroma-js/src/io/num.coffee generated vendored Normal file
View file

@ -0,0 +1,14 @@
# @require utils num2rgb rgb2num
chroma.num = (num) ->
new Color num, 'num'
Color::num = (mode='rgb') ->
rgb2num @_rgb, mode
_input.num = num2rgb
_guess_formats.push
p: 1,
test: (n) ->
'num' if arguments.length == 1 and type(n) == "number" and n >= 0 and n <= 0xFFFFFF

21
src/static/node_modules/chroma-js/src/io/rgb.coffee generated vendored Normal file
View file

@ -0,0 +1,21 @@
# @require utils
_input.rgb = () ->
(v for k,v of unpack arguments)
chroma.rgb = () ->
new Color arguments..., 'rgb'
Color::rgb = (round=true) ->
if round then @_rgb.map(Math.round).slice 0,3 else @_rgb.slice 0,3
Color::rgba = (round=true) ->
return @_rgb.slice(0) if not round
return [Math.round(@_rgb[0]), Math.round(@_rgb[1]), Math.round(@_rgb[2]), @_rgb[3]]
_guess_formats.push
p: 3
test: (n) ->
a = unpack arguments
return 'rgb' if type(a) == 'array' and a.length == 3
return 'rgb' if a.length == 4 and type(a[3]) == "number" and a[3] >= 0 and a[3] <= 1

View file

@ -0,0 +1,12 @@
# @requires utils rgb2temperature temperature2rgb
chroma.temperature = chroma.kelvin = () ->
new Color arguments..., 'temperature'
_input.temperature = _input.kelvin = _input.K = temperature2rgb
Color::temperature = () ->
rgb2temperature @_rgb
Color::kelvin = Color::temperature

172
src/static/node_modules/chroma-js/src/limits.coffee generated vendored Normal file
View file

@ -0,0 +1,172 @@
chroma.analyze = (data, key, filter) ->
r =
min: Number.MAX_VALUE
max: Number.MAX_VALUE*-1
sum: 0
values: []
count: 0
if not filter?
filter = ->
true
add = (val) ->
if val? and not isNaN val
r.values.push val
r.sum += val
r.min = val if val < r.min
r.max = val if val > r.max
r.count += 1
return
visit = (val, k) ->
if filter val, k
if key? and type(key) == 'function'
add key val
else if key? and type(key) == 'string' or type(key) == 'number'
add val[key]
else
add val
if type(data) == 'array'
for val in data
visit val
else
for k, val of data
visit val, k
r.domain = [r.min, r.max]
r.limits = (mode, num) ->
chroma.limits r, mode, num
r
chroma.limits = (data, mode='equal', num=7) ->
if type(data) == 'array'
data = chroma.analyze data
min = data.min
max = data.max
sum = data.sum
values = data.values.sort (a,b)->
a-b
return [min,max] if num == 1
limits = []
if mode.substr(0,1) == 'c' # continuous
limits.push min
limits.push max
if mode.substr(0,1) == 'e' # equal interval
limits.push min
for i in [1..num-1]
limits.push min+(i/num)*(max-min)
limits.push max
else if mode.substr(0,1) == 'l' # log scale
if min <= 0
throw 'Logarithmic scales are only possible for values > 0'
min_log = Math.LOG10E * log min
max_log = Math.LOG10E * log max
limits.push min
for i in [1..num-1]
limits.push pow 10, min_log + (i/num) * (max_log - min_log)
limits.push max
else if mode.substr(0,1) == 'q' # quantile scale
limits.push min
for i in [1..num-1]
p = (values.length-1) * i/num
pb = floor p
if pb == p
limits.push values[pb]
else # p > pb
pr = p - pb
limits.push values[pb]*(1-pr) + values[pb+1]*pr
limits.push max
else if mode.substr(0,1) == 'k' # k-means clustering
###
implementation based on
http://code.google.com/p/figue/source/browse/trunk/figue.js#336
simplified for 1-d input values
###
n = values.length
assignments = new Array n
clusterSizes = new Array num
repeat = true
nb_iters = 0
centroids = null
# get seed values
centroids = []
centroids.push min
for i in [1..num-1]
centroids.push min + (i/num) * (max-min)
centroids.push max
while repeat
# assignment step
for j in [0..num-1]
clusterSizes[j] = 0
for i in [0..n-1]
value = values[i]
mindist = Number.MAX_VALUE
for j in [0..num-1]
dist = abs centroids[j]-value
if dist < mindist
mindist = dist
best = j
clusterSizes[best]++
assignments[i] = best
# update centroids step
newCentroids = new Array num
for j in [0..num-1]
newCentroids[j] = null
for i in [0..n-1]
cluster = assignments[i]
if newCentroids[cluster] == null
newCentroids[cluster] = values[i]
else
newCentroids[cluster] += values[i]
for j in [0..num-1]
newCentroids[j] *= 1/clusterSizes[j]
# check convergence
repeat = false
for j in [0..num-1]
if newCentroids[j] != centroids[i]
repeat = true
break
centroids = newCentroids
nb_iters++
if nb_iters > 200
repeat = false
# finished k-means clustering
# the next part is borrowed from gabrielflor.it
kClusters = {}
for j in [0..num-1]
kClusters[j] = []
for i in [0..n-1]
cluster = assignments[i]
kClusters[cluster].push values[i]
tmpKMeansBreaks = []
for j in [0..num-1]
tmpKMeansBreaks.push kClusters[j][0]
tmpKMeansBreaks.push kClusters[j][kClusters[j].length-1]
tmpKMeansBreaks = tmpKMeansBreaks.sort (a,b)->
a-b
limits.push tmpKMeansBreaks[0]
for i in [1..tmpKMeansBreaks.length-1] by 2
v = tmpKMeansBreaks[i]
if not isNaN(v) and limits.indexOf(v) == -1
limits.push v
limits

View file

@ -0,0 +1,6 @@
# @require color
Color::alpha = (a) ->
if arguments.length
return chroma.rgb([@_rgb[0], @_rgb[1], @_rgb[2], a])
@_rgb[3]

68
src/static/node_modules/chroma-js/src/ops/blend.coffee generated vendored Normal file
View file

@ -0,0 +1,68 @@
#
# interpolates between a set of colors uzing a bezier spline
# blend mode formulas taken from http://www.venture-ware.com/kevin/coding/lets-learn-math-photoshop-blend-modes/
#
# @require utils color
blend = (bottom, top, mode) ->
if !blend[mode]
throw 'unknown blend mode ' + mode
blend[mode](bottom, top)
blend_f = (f) ->
(bottom,top) ->
c0 = chroma(top).rgb()
c1 = chroma(bottom).rgb()
chroma(f(c0,c1), 'rgb')
each = (f) ->
(c0, c1) ->
out = []
for i in [0..3]
out[i] = f(c0[i], c1[i])
out
normal = (a,b) ->
a
multiply = (a,b) ->
a * b / 255
darken = (a,b) ->
if a > b then b else a
lighten = (a,b) ->
if a > b then a else b
screen = (a,b) ->
255 * (1 - (1-a/255) * (1-b/255))
overlay = (a,b) ->
if b < 128
2 * a * b / 255
else
255 * (1 - 2 * (1 - a / 255 ) * ( 1 - b / 255 ))
burn = (a,b) ->
255 * (1 - (1 - b / 255) / (a/255))
dodge = (a,b) ->
return 255 if a == 255
a = 255 * (b / 255) / (1 - a / 255)
if a > 255 then 255 else a
# add = (a,b) ->
# if (a + b > 255) then 255 else a + b
blend.normal = blend_f each normal
blend.multiply = blend_f each multiply
blend.screen = blend_f each screen
blend.overlay = blend_f each overlay
blend.darken = blend_f each darken
blend.lighten = blend_f each lighten
blend.dodge = blend_f each dodge
blend.burn = blend_f each burn
# blend.add = blend_f each add
chroma.blend = blend

View file

@ -0,0 +1,4 @@
# @require color
Color::clipped = () ->
@_rgb._clipped or false

Some files were not shown because too many files have changed in this diff Show more