Skip to content

Instantly share code, notes, and snippets.

@toja
Last active June 3, 2016 12:04
Show Gist options
  • Save toja/7a6b92ba0519ab07f6a909a7ba9eeb6e to your computer and use it in GitHub Desktop.
Save toja/7a6b92ba0519ab07f6a909a7ba9eeb6e to your computer and use it in GitHub Desktop.
4096 Random Colors - Histogram (DeltaE00)
height: 480
license: gpl-3.0
// code adapted from https://github.com/zschuessler/DeltaE
function dE00(x1,x2){var sqrt=Math.sqrt;var pow=Math.pow;this.x1=x1;this.x2=x2;this.deltaLPrime=x2.l-x1.l;this.LBar=(x1.l+x2.l)/2;this.C1=sqrt(pow(x1.a,2)+pow(x1.a,2));this.C2=sqrt(pow(x2.b,2)+pow(x2.b,2));this.CBar=(this.C1+this.C2)/2;this.aPrime1=x1.a+x1.a/2*(1-sqrt(pow(this.CBar,7)/(pow(this.CBar,7)+pow(25,7))));this.aPrime2=x2.a+x2.a/2*(1-sqrt(pow(this.CBar,7)/(pow(this.CBar,7)+pow(25,7))));this.CPrime1=sqrt(pow(this.aPrime1,2)+pow(x1.b,2));this.CPrime2=sqrt(pow(this.aPrime2,2)+pow(x2.b,2));this.CBarPrime=(this.CPrime1+this.CPrime2)/2;this.deltaCPrime=this.CPrime2-this.CPrime1;this.SsubL=1+.015*pow(this.LBar-50,2)/sqrt(20+pow(this.LBar-50,2));this.SsubC=1+.045*this.CBarPrime;this.hPrime1=0;this.hPrime2=0;this.deltahPrime=0;this.deltaHPrime=0;this.HBarPrime=0;this.T=0;this.SsubH=0;this.RsubT=0}dE00.prototype.getDeltaE=function(){var sqrt=Math.sqrt;var sin=Math.sin;var pow=Math.pow;this.hPrime1=this.gethPrime1();this.hPrime2=this.gethPrime2();this.deltahPrime=this.getDeltahPrime();this.deltaHPrime=2*sqrt(this.CPrime1*this.CPrime2)*sin(this.degreesToRadians(this.deltahPrime)/2);this.HBarPrime=this.getHBarPrime();this.T=this.getT();this.SsubH=1+.015*this.CBarPrime*this.T;this.RsubT=this.getRsubT();var lightness=this.deltaLPrime/this.SsubL;var chroma=this.deltaCPrime/this.SsubC;var hue=this.deltaHPrime/this.SsubH;return sqrt(pow(lightness,2)+pow(chroma,2)+pow(hue,2)+this.RsubT*chroma*hue)};dE00.prototype.getRsubT=function(){var sin=Math.sin;var sqrt=Math.sqrt;var pow=Math.pow;var exp=Math.exp;return-2*sqrt(pow(this.CBarPrime,7)/(pow(this.CBarPrime,7)+pow(25,7)))*sin(this.degreesToRadians(60*exp(-pow((this.HBarPrime-275)/25,2))))};dE00.prototype.getT=function(){var cos=Math.cos;return 1-.17*cos(this.degreesToRadians(this.HBarPrime-30))+.24*cos(this.degreesToRadians(2*this.HBarPrime))+.32*cos(this.degreesToRadians(3*this.HBarPrime+6))-.2*cos(this.degreesToRadians(4*this.HBarPrime-63))};dE00.prototype.getHBarPrime=function(){var abs=Math.abs;if(abs(this.hPrime1-this.hPrime2)>180){return(this.hPrime1+this.hPrime2+360)/2}return(this.hPrime1+this.hPrime2)/2};dE00.prototype.getDeltahPrime=function(){var abs=Math.abs;if(0===this.C1||0===this.C2){return 0}if(abs(this.hPrime1-this.hPrime2)<=180){return this.hPrime2-this.hPrime1}if(this.hPrime2<=this.hPrime1){return this.hPrime2-this.hPrime1+360}else{return this.hPrime2-this.hPrime1-360}};dE00.prototype.gethPrime1=function(){return this._gethPrimeFn(this.x1.b,this.aPrime1)};dE00.prototype.gethPrime2=function(){return this._gethPrimeFn(this.x2.b,this.aPrime2)};dE00.prototype._gethPrimeFn=function(x,y){var hueAngle;if(x===0&&y===0){return 0}hueAngle=this.radiansToDegrees(Math.atan2(x,y));if(hueAngle>=0){return hueAngle}else{return hueAngle+360}};dE00.prototype.radiansToDegrees=function(radians){return radians*(180/Math.PI)};dE00.prototype.degreesToRadians=function(degrees){return degrees*(Math.PI/180)};
<!DOCTYPE html>
<meta charset="utf-8">
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="deltaE00.min.js"></script>
<body>
<script>
var width = 960,
height = 480,
grid = [32,32],
space = 1.0,
deltaMin = 3.0,
numColors = 4096;
var binWidth = width / grid[0] - space * 2,
binHeight = height / grid[1] - space * 2;
var x = d3.scale.linear()
.domain([0, 360])
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xz = d3.range(0, width, width / grid[0]),
yz = d3.range(0, height, height / grid[1]);
var bins = yz.map(function(y) { return xz.map(function(x) { return { x: x, y: y, z: 0 }; }); });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("g")
.selectAll(".bins")
.data(d3.merge(bins))
.enter().append("rect")
.attr("id", function (d) { return "x" + d.x + "y" + d.y; })
.attr("x", function (d) { return d.x + space; })
.attr("y", function (d) { return d.y + space; })
.attr("width", binWidth)
.attr("height", binHeight)
.style("fill", function (d) { return d3.rgb(255 - d.z, 255 - d.z, 255 - d.z).toString(); });
var dots = svg.append("g")
var sample = colorSampler(numColors);
colors = [];
d3.timer(function() {
var hsl = sample();
if (!hsl) return true;
var cx = x(hsl.h),
cy = y(hsl.l);
dots.append("circle")
.attr("cx", cx)
.attr("cy", cy)
.attr("r", 8)
.style("fill", hsl.toString())
.transition()
.attr("r", 0);
var col = Math.floor((cx / width) * grid[0]),
row = Math.floor((cy / height) * grid[1]),
bin = bins[row][col],
id = "x" + bin.x + "y" + bin.y;
bin.z += 8;
d3.select("#" + id)
.style("fill", d3.rgb(255 - bin.z, 255 - bin.z, 255 - bin.z).toString());
});
function colorSampler(numSamplesMax) {
return function() {
if (colors.length > numSamplesMax) return;
do {
var hsl = d3.hsl(d3.rgb(
Math.floor(Math.random() * 256),
Math.floor(Math.random() * 256),
Math.floor(Math.random() * 256)
));
var lab = d3.lab(hsl);
}
while (!hsl.h || !isValidColor(lab));
colors.push(lab);
return hsl;
};
}
function isValidColor(lab) {
if (colors.length == 0) return true;
for (i = 0; i < colors.length; i++) {
var delta = new dE00(lab, colors[i]).getDeltaE();
if (delta < deltaMin)
return false;
}
return true;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment