This bl.ock builds upon HSL Color Picker
by Mike Bostock and i want hue
by Médialab.
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
* { box-sizing: border-box; }
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
p, svg text, label {
font-size: 13px;
font-family: sans-serif; }
svg { overflow: visible; }
.left-container {
display: inline-block;
width: 360px;
vertical-align: top;
}
.right-container {
display: inline-block;
width: 540px;
padding-left: 16px;
}
input[type="number"] {
outline: none;
border: none;
border-bottom: 1px solid #DDD;
text-align: right;
font-size: 13px;
width: 32px; }
input[type="range"] {
width: 100%;
}
svg.gradient {
width: 360px;
height: 20px;
}
svg.gradient {
stroke: none;
}
svg.hue-ctrl .hue-ticks circle {
stroke: #999;
stroke-width: 1.5px;
}
svg.hue-ctrl .hue-ticks circle:first-of-type {
stroke: black;
cursor: move;
}
.color-list {
font-family: monospace;
padding: 8px;
background: #F9F9F9;
}
.state-map .state {
stroke: #666;
stroke-width: 0.5px;
}
.sparklines path {
stroke-width: 2px;
fill: none;
}
.axis {
stroke: black;
shape-rendering: crispEdges;
}
</style>
<div class='left-container'>
<p>
Build a palette of
<input type='number'
dimension='nColors'
value='6' min='1' max='360' /> colors, with<br />
Saturation: <span class='s-value'>50</span>%
<svg class='gradient saturation'></svg>
<input class='s-ctrl'
dimension='saturation'
type='range'
min='0' max='1' step='0.01' value='0.66'><br />
Lightness: <span class='l-value'>66</span>%
<svg class='gradient lightness'></svg>
<input class='l-ctrl'
dimension='lightness'
type='range'
min='0' max='1' step='0.01' value='0.66'>
</p>
<svg class='hue-ctrl' width='360' height='360'></svg>
</div>
<div class='right-container'>
<p class='color-list'></p>
<svg class='state-map' width='540' height='300'></svg>
<svg width='540' height='140'>
<line class='axis' x1='0' x2='540' y1='70' y2='70' />
<line class='axis' x1='0' x2='0' y1='0' y2='140' />
<g class='sparklines'></g>
</svg>
</div>
</head>
<body>
<script>
// equidistant hues, same saturation and lightness
function palette(nColors, dHue, saturation, lightness) {
return d3.range((0 + dHue), (360 + dHue), (360 / nColors))
.map(function(hue) {
hue = hue % 360;
var hslObj = d3.hsl(hue, saturation, lightness);
return {
h: hue,
s: saturation,
l: lightness,
_: hslObj,
rgb: hslObj.toString()
};
});
}
//
// state, data
var _palette = [],
_input = {
nColors: 5,
dHue: 0,
saturation: 0.80,
lightness: 0.80
};
//
// misc constants
var radToDeg = 180 / Math.PI,
tau = Math.PI * 2;
//
// rendering
var hueCtrl = d3.select('svg.hue-ctrl'),
hueWidth = 360,
hueCenter = hueWidth / 2,
r0 = 170,
r1 = r0 - 32,
arcs = 360,
gradientWidth = 360,
gradientRects = 100,
hueDrag = d3.behavior.drag();
hueCtrl.append('g')
.attr('class', 'hue-arcs')
.selectAll("path")
.data(d3.range(0, tau, tau / arcs))
.enter().append("path")
.attr("d", d3.svg.arc().innerRadius(r0).outerRadius(r1)
.startAngle(function(d) { return d; })
.endAngle(function(d) { return d + tau / arcs * 1.1; }));
hueCtrl.append('g').attr('class', 'hue-ticks');
hueCtrl.append('text').attr('text-anchor', 'middle');
hueCtrl.selectAll('g, text').attr('transform',
'translate(' + hueCenter + ',' + hueCenter + ')');
var lGradient = d3.select('svg.gradient.lightness'),
sGradient = d3.select('svg.gradient.saturation'),
gradientDx = 360 / gradientRects;
d3.selectAll('svg.gradient').selectAll('rect')
.data(d3.range(0, gradientWidth, gradientDx))
.enter().append('rect')
.attr('x', function(d) { return d; })
.attr('height', 20)
.attr('width', gradientDx + 0.33);
//
// drag to change initial hue
var _theta0, _dHue0;
hueDrag
.on('dragstart', function() {
var x = d3.mouse(this)[0] - hueCenter,
y = d3.mouse(this)[1] - hueCenter;
_theta0 = Math.atan2(-y, x) * radToDeg;
_dHue0 = _input.dHue;
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function() {
var x = d3.mouse(this)[0] - hueCenter,
y = d3.mouse(this)[1] - hueCenter,
theta = Math.atan2(-y, x) * radToDeg,
dTheta = _theta0 - theta;
_input.dHue = _dHue0 + dTheta;
update();
});
hueCtrl.call(hueDrag);
// bind <input> controls
d3.selectAll('input[dimension]')
.on('input', function() {
_input[this.getAttribute('dimension')] = +this.value;
update();
});
//
// cache selectors, make updates
var hueArcSel = hueCtrl.selectAll('.hue-arcs path'),
hueTicks = hueCtrl.select('.hue-ticks'),
sValues = d3.selectAll('.s-value'),
lValues = d3.selectAll('.l-value'),
lTicks = lGradient.selectAll('rect'),
sTicks = sGradient.selectAll('rect'),
hueValue = hueCtrl.select('text'),
colorList = d3.selectAll('.color-list');
// render sparklines
var sparkSvg = d3.select('.sparklines'),
sparkWidth = 540,
sparkHeight = 140,
nPoints = 20,
sparkdX = sparkWidth / nPoints;
sparkPath = function() {
return 'M0,'+(sparkHeight / 2)+' '+
d3.range(0, nPoints)
.map(function() {
return 'l'+sparkdX +','+((0.5 - Math.random())* sparkHeight / 8); })
.join(' ');
};
function update() {
hueArcSel.style('fill', function(d) { return d3.hsl((d * 360) / tau,
_input.saturation,
_input.lightness); });
lTicks.style('fill', function(d, ndx) { return d3.hsl(_input.dHue,
_input.saturation,
(ndx * .01)); });
sTicks.style('fill', function(d, ndx) { return d3.hsl(_input.dHue,
(ndx * .01),
_input.lightness); });
sValues.text(Math.round(_input.saturation * 100));
lValues.text(Math.round(_input.lightness * 100));
hueValue.text(Math.round(_input.dHue) + '° base hue, ' +
Math.round(360/_input.nColors) + '° between swatches');
_palette = palette(_input.nColors,
_input.dHue,
_input.saturation,
_input.lightness);
colorList.text('var swatches = [' +
_palette.map(function(d) { return d.rgb; }).join(', ') +
'];');
var tickSel = hueTicks.selectAll('circle').data(_palette);
tickSel.exit().remove();
tickSel.enter().append('circle')
.attr('r', 9.5)
.attr('cx', 0)
.attr('cy', (r0 + r1) / -2);
tickSel
.style('fill', function(d) { return d.rgb; })
.attr('transform', function(d) {
return 'rotate('+(d.h)+' 0 0)'
});
var sparkSel = sparkSvg.selectAll('path').data(_palette);
sparkSel.exit().remove();
sparkSel.enter().append('path').attr('d', sparkPath);
sparkSel.style('stroke', function(d) { return d.rgb; });
d3.select('.state-map').selectAll('path.state')
.style('fill', function(d, ndx) {
// return _palette[Math.floor(Math.random() * _palette.length)].rgb;
// ^^ warning, can induce seizures
return _palette[ndx % _palette.length].rgb;
});
}
update();
//
// states
d3.json('us_states.json', function(err, statejson) {
var mapWidth = 580,
mapHeight = 300,
projection = d3.geo.albersUsa()
.scale(mapWidth)
.translate([mapWidth / 2, mapHeight / 2]);
var path = d3.geo.path().projection(projection);
d3.select('.state-map').selectAll('path.state')
.data(statejson.features).enter()
.append('path')
.attr('class', 'state')
.attr('d', function(d) { return path(d); });
update();
});
</script>
</body>
https://d3js.org/d3.v3.min.js