<div class='outer-wrap round'>
<ul class='quadrants fill'>
<li class='q'>Q I</li>
<li class='q'>Q II</li>
<li class='q'>Q III</li>
<li class='q'>Q IV</li>
</ul>
<div class='box centre-me'></div>
<div class='axis angle-start-axis centre-me'></div>
<div class='axis h-axis centre-me'></div>
<div class='moving-line grad-line centre-me'></div>
<div class='moving-line grad-start centre-me'></div>
<div class='moving-line grad-end centre-me'></div>
<ul class='angles fill round'></ul>
</div>
<code class='grad-code'></code>
<p>
Demo by <a href="http://codepen.io/thebabydino">Ana Tudor</a>. Licensed under MIT.
</p>
html,
body {
min-width: 240px;
min-height: 240px;
height: 100%;
margin: 0;
}
html {
font: .8em Verdana, sans-serif;
text-align: center;
}
body {
padding: 20px;
}
.centre-me {
position: absolute;
top: 50%;
left: 50%;
}
.fill {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 0;
}
.round {
border-radius: 50%;
}
.outer-wrap {
position: relative;
margin: 4em auto 0;
}
.outer-wrap ul {
list-style: none;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.q {
position: absolute;
font-weight: 700;
}
.q:first-child {
top: -1em;
right: -1em;
}
.q:nth-child(2) {
right: -1em;
bottom: -1em;
}
.q:nth-child(3) {
bottom: -1em;
left: -1em;
}
.q:nth-child(4) {
top: -1em;
left: -1em;
}
.angles {
-webkit-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.angle {
margin: -1px;
border: solid 1px;
cursor: pointer;
-webkit-transition: box-shadow .3s;
transition: box-shadow .3s;
}
.angle:after {
position: absolute;
top: 50%;
left: 50%;
margin: -7px;
width: 14px;
height: 14px;
border-radius: 50%;
content: '';
}
.angle:before {
position: absolute;
top: -10px;
left: 11px;
padding: 0 3px;
border-radius: 4px;
box-shadow: 0 0 2px;
background: -webkit-linear-gradient(whitesmoke, gainsboro);
background: linear-gradient(whitesmoke, gainsboro);
color: black;
}
.sec:before {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
}
.angle:hover,
.selected {
box-shadow: 0 0 1px 3px crimson, 0 0 1px 5px white, 0 0 1px 7px crimson;
}
.angle:hover:before,
.selected:before {
content: attr(data-angle) '°';
}
.major {
margin: -2px;
border: solid 2px;
color: crimson;
}
.box {
margin: -15% -30%;
width: 60%;
height: 30%;
background: -webkit-linear-gradient(90deg, deeppink, yellow, springgreen);
background: linear-gradient(0deg, deeppink, yellow, springgreen);
-webkit-transition: background-image .75s linear;
transition: background-image .75s linear;
}
.axis {
top: -50px;
bottom: -50px;
width: 1px;
background: dimgrey;
}
.angle-start-axis:before {
display: block;
min-width: 125px;
text-align: left;
text-indent: 2px;
content: '← angle start axis';
}
.h-axis {
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
.grad-line {
top: 12px;
bottom: 12px;
width: 1px;
background: dodgerblue;
-webkit-transition: -webkit-transform .75s linear;
transition: -webkit-transform .75s linear;
transition: transform .75s linear;
}
.grad-line:before {
display: block;
margin-top: 7px;
min-width: 105px;
text-align: left;
text-indent: 2px;
content: '← gradient line';
}
.rev:before {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
content: 'gradient line →';
}
.grad-start,
.grad-end {
left: 20%;
right: 20%;
height: 1px;
background: crimson;
-webkit-transition: .75s linear;
transition: .75s linear;
}
.grad-end {
background: black;
}
.grad-code {
display: inline-block;
position: relative;
z-index: 1;
margin-top: 3em;
padding: .5em;
background: black;
color: white;
font: 1.25em monospace;
}
@media (min-width: 240px) {
html {
overflow-x: hidden;
}
}
(function() {
var fullCircle = 360,
Demo = function() {
// utility class
var EUtil = function() {
this.getSize = function(m /* integer */) {
var w = document.body.clientWidth, h = document.body.clientHeight, s;
s = Math.max(Math.min(Math.min(w,h) - m - 96, 640), 199);
return (s%2 !== 0)?s:(s-1);
}
this.setStyle = function(elStyles) {
/*
elStyles is an array
[
[element_1, {property_1_1: value_1_1, property_1_2: value_1_2}],
[element_2, {property_2_1: value_2_1}]
]
*/
var t, len = elStyles.length,
prefixed = {'property': ['transform'], 'value': ['linear-gradient']},
prefixList = ['-webkit-', '-moz', '-o-'], l = prefixList.length;
for(var i = 0; i < len; i++) {
for(var p in elStyles[i][1]) {
if(prefixed['property'][0].indexOf(p) != -1) { /* check if the property needs to be prefixed */
for(var j = 0; j < l; j++)
elStyles[i][0].style[prefixList[j] + p] = elStyles[i][1][p];
}
if(elStyles[i][1][p].indexOf(prefixed['value'][0]) != -1) { /* check if the value needs to be prefixed */
t = 90 - parseInt(elStyles[i][1][p].split(prefixed['value'][0]+'(')[1].split('deg')[0], 10);
t = prefixed['value'][0] + '(' + t + 'deg' + elStyles[i][1][p].split('deg')[1];
for(var j = 0; j < l; j++)
elStyles[i][0].style[p] = prefixList[j] + t;
}
elStyles[i][0].style[p] = elStyles[i][1][p]; /* just set styles, no prefixes */
}
}
};
};
// angle class
var Angle = function(angleValue, u, r) {
var value = angleValue,
selected = (angleValue === 0)?true:false,
el = document.createElement('li'); /* this is a dot on the circle */
el.setAttribute('class', 'angle centre-me round');
this.isSelected = function() { return selected; };
this.select = function() { selected = true; el.classList.add('selected'); };
this.unselect = function() { selected = false; el.classList.remove('selected'); };
this.getValue = function() { return value; };
this.getElement = function() { return el; };
this.isMajor = function() { return value%15 === 0; };
this.isSec = function() { return value > 180; };
if(this.isMajor()) el.classList.add('major');
if(this.isSec()) el.classList.add('sec');
if(this.isSelected()) el.classList.add('selected');
if(el.dataset) el.dataset.angle = value;
else el.setAttribute('data-angle', value);
u.setStyle([[el, {'transform': 'rotate(' + value + 'deg) translate(' + r + 'px)'}]]);
};
var AngleCircle = function() {
var angles = [], currentAngle,
getSensitivity = function(size) {
if(size < 240) return 15; /* every 15° for smallest screen */
if(size < 320) return 10; /* every 10° */
if(size < 480) return 6;
if(size < 560) return 5;
return 3;
}
this.createCircle = function(parent, u) {
var parentStyle = window.getComputedStyle(parent, null),
margin = parseInt(parentStyle.marginTop.split('px')[0], 10) + 36,
size = u.getSize(margin), r = size/2, s = getSensitivity(size),
listWrap = parent.querySelector('.angles');
u.setStyle([[parent, {'width': size + 'px', 'height': size + 'px'}]]);
listWrap.innerHTML = '';
listWrap = parent.removeChild(listWrap);
for(var i = 0; i < fullCircle/s; i++) {
currentAngle = new Angle(i*s, u, r);
angles.push(currentAngle);
listWrap.appendChild(currentAngle.getElement());
}
parent.appendChild(listWrap);
};
this.getSelected = function() {
var len = angles.length;
for(var i = 0; i < len; i++)
if(angles[i].isSelected()) return angles[i];
console.log('error, no angle selected :(');
return null;
};
this.getAngle = function(angleValue) {
var len = angles.length;
for(var i = 0; i < len; i++)
if(angles[i].getValue() == angleValue) return angles[i];
console.log('error, no angle with such value :(');
return null;
};
this.select = function(angleValue) {
var len = angles.length, selectedAngle = this.getSelected();
if(angleValue == selectedAngle.getValue()) {
console.log('already selected :)');
return -1;
}
this.getAngle(angleValue).select();
selectedAngle.unselect();
};
};
this.init = function() {
var u = new EUtil(), wrap = document.querySelector('.outer-wrap'),
box = wrap.querySelector('.box'),
codeEl = document.querySelector('.grad-code'),
codetxt = 'linear-gradient(0deg, deeppink, yellow, lime)',
gradLine = document.querySelector('.grad-line'),
gradStart = document.querySelector('.grad-start'),
gradEnd = document.querySelector('.grad-end'),
angleCircle = new AngleCircle(), currentAngle = 0;
angleCircle.createCircle(wrap, u);
u.setStyle([[gradLine, {'transform': 'rotate(0)'}],
[gradStart, {'transform': 'rotate(0)', 'left': '-10%', 'right': '50%', 'top': '65%'}],
[gradEnd, {'transform': 'rotate(0)', 'left': '50%', 'right': '-10%', 'top': '35%'}],
[box, {'backgroundImage': codetxt}]]);
codeEl.innerHTML = codetxt;
if(gradLine.classList.contains('rev')) gradLine.classList.remove('rev');
wrap.addEventListener('click', function(e) {
var t = e.target, a, dif;
if(t.classList.contains('angle')) {
if(t.dataset) a = parseInt(t.dataset.angle, 10);
else a = parseInt(t.getAttribute('data-angle'), 10);
if(angleCircle.select(a) == -1) return;
dif = a - currentAngle%360;
currentAngle += (Math.abs(dif) > 180) ? (Math.abs(dif) - 360)*Math.abs(dif)/dif : dif;
codetxt = 'linear-gradient(' + currentAngle + 'deg, deeppink, yellow, lime)';
u.setStyle([[gradLine, {'transform': 'rotate(' + currentAngle + 'deg)'}],
[gradStart, {'transform': 'rotate(' + currentAngle + 'deg)'}],
[gradEnd, {'transform': 'rotate(' + currentAngle + 'deg)'}],
[box, {'backgroundImage': codetxt}]]);
codetxt = 'linear-gradient(' + ((currentAngle%360>=0)?(currentAngle%360):(360+currentAngle%360)) + 'deg, deeppink, yellow, lime)';
codeEl.innerHTML = codetxt;
if(a > 90 && a < 270) gradLine.classList.add('rev');
else gradLine.classList.remove('rev');
if(a >= 0 && a < 90)
u.setStyle([[gradStart, {'left': '-10%', 'right': '50%', 'top': '65%'}],
[gradEnd, {'left': '50%', 'right': '-10%', 'top': '35%'}]]);
if(a >= 90 && a < 180)
u.setStyle([[gradStart, {'left': '-10%', 'right': '50%', 'top': '35%'}],
[gradEnd, {'left': '50%', 'right': '-10%', 'top': '65%'}]]);
if(a >= 180 && a < 270)
u.setStyle([[gradStart, {'left': '50%', 'right': '-10%', 'top': '35%'}],
[gradEnd, {'left': '-10%', 'right': '50%', 'top': '65%'}]]);
if(a >= 270 && a < 360)
u.setStyle([[gradStart, {'left': '50%', 'right': '-10%', 'top': '65%'}],
[gradEnd, {'left': '-10%', 'right': '50%', 'top': '35%'}]]);
}
}, false);
};
}
var d = new Demo();
d.init();
window.addEventListener('resize', function(e) { d.init(); }, false);
}());