Finally created an entry for #neonHexagonsWeekend. Move cursor.
Also, you can take a look at what other lovely people have created for this themed weekend.
<canvas></canvas> | |
<canvas></canvas> |
Finally created an entry for #neonHexagonsWeekend. Move cursor.
Also, you can take a look at what other lovely people have created for this themed weekend.
/* because me lazy */ | |
Object.getOwnPropertyNames(Math).map(function(p) { | |
window[p] = Math[p]; | |
}); | |
var HEX_CRAD = 32, | |
HEX_BG = '#171717', | |
HEX_HL = '#2a2a2a', | |
HEX_HLW = 2, | |
HEX_GAP = 4, | |
NEON_PALETE = [ | |
'#cb3301', '#ff0066', | |
'#ff6666', '#feff99', | |
'#ffff67', '#ccff66', | |
'#99fe00', '#fe99ff', | |
'#ff99cb', '#fe349a', | |
'#cc99fe', '#6599ff', | |
'#00ccff', '#ffffff' | |
], | |
T_SWITCH = 64, | |
unit_x = 3*HEX_CRAD + HEX_GAP*sqrt(3), | |
unit_y = HEX_CRAD*sqrt(3)*.5 + .5*HEX_GAP, | |
off_x = 1.5*HEX_CRAD + HEX_GAP*sqrt(3)*.5, | |
/* extract a work palette */ | |
wp = NEON_PALETE.map(function(c) { | |
var num = parseInt(c.replace('#', ''), 16); | |
return { | |
'r': num >> 16 & 0xFF, | |
'g': num >> 8 & 0xFF, | |
'b': num & 0xFF | |
}; | |
}), | |
nwp = wp.length, csi = 0, | |
f = 1/T_SWITCH, | |
c = document.querySelectorAll('canvas'), | |
n = c.length, w, h, _min, | |
ctx = [], | |
grid, source = null, | |
t = 0, request_id = null; | |
var GridItem = function(x, y) { | |
this.x = x || 0; | |
this.y = y || 0; | |
this.points = { 'hex': [], 'hl': [] }; | |
this.init = function() { | |
var x, y, a, ba = PI/3, | |
ri = HEX_CRAD - .5*HEX_HLW; | |
for(var i = 0; i < 6; i++) { | |
a = i*ba; | |
x = this.x + HEX_CRAD*cos(a); | |
y = this.y + HEX_CRAD*sin(a); | |
this.points.hex.push({ | |
'x': x, | |
'y': y | |
}); | |
if(i > 2) { | |
x = this.x + ri*cos(a); | |
y = this.y + ri*sin(a); | |
this.points.hl.push({ | |
'x': x, | |
'y': y | |
}); | |
} | |
} | |
}; | |
this.draw = function(ct) { | |
for(var i = 0; i < 6; i++) { | |
ct[(i === 0?'move':'line')+ 'To']( | |
this.points.hex[i].x, | |
this.points.hex[i].y | |
); | |
} | |
}; | |
this.highlight = function(ct) { | |
for(var i = 0; i < 3; i++) { | |
ct[(i === 0?'move':'line')+ 'To']( | |
this.points.hl[i].x, | |
this.points.hl[i].y | |
); | |
} | |
}; | |
this.init(); | |
}; | |
var Grid = function(rows, cols) { | |
this.cols = cols || 16; | |
this.rows = rows || 16; | |
this.items = []; | |
this.n = this.items.length; | |
this.init = function() { | |
var x, y; | |
for(var row = 0; row < this.rows; row++) { | |
y = row*unit_y; | |
for(var col = 0; col < this.cols; col++) { | |
x = ((row%2 == 0)?0:off_x) + col*unit_x; | |
this.items.push(new GridItem(x, y)); | |
} | |
} | |
this.n = this.items.length; | |
}; | |
this.draw = function(ct) { | |
ct.fillStyle = HEX_BG; | |
ct.beginPath(); | |
for(var i = 0; i < this.n; i++) { | |
this.items[i].draw(ct); | |
} | |
ct.closePath(); | |
ct.fill(); | |
ct.strokeStyle = HEX_HL; | |
ct.beginPath(); | |
for(var i = 0; i < this.n; i++) { | |
this.items[i].highlight(ct); | |
} | |
ct.closePath(); | |
ct.stroke(); | |
}; | |
this.init(); | |
}; | |
var init = function() { | |
var s = getComputedStyle(c[0]), | |
rows, cols; | |
w = ~~s.width.split('px')[0]; | |
h = ~~s.height.split('px')[0]; | |
_min = .75*min(w, h); | |
rows = ~~(h/unit_y) + 2; | |
cols = ~~(w/unit_x) + 2; | |
for(var i = 0; i < n; i++) { | |
c[i].width = w; | |
c[i].height = h; | |
ctx[i] = c[i].getContext('2d'); | |
} | |
grid = new Grid(rows, cols); | |
grid.draw(ctx[1]); | |
if(!source) { | |
source = { 'x': ~~(w/2), 'y': ~~(h/2) }; | |
} | |
neon(); | |
}; | |
var neon = function() { | |
var k = (t%T_SWITCH)*f, | |
rgb = { | |
'r': ~~(wp[csi].r*(1 - k) + | |
wp[(csi + 1)%nwp].r*k), | |
'g': ~~(wp[csi].g*(1 - k) + | |
wp[(csi + 1)%nwp].g*k), | |
'b': ~~(wp[csi].b*(1 - k) + | |
wp[(csi + 1)%nwp].b*k) | |
}, | |
rgb_str = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')', | |
light = ctx[0].createRadialGradient( | |
source.x, source.y, 0, | |
source.x, source.y, .875*_min | |
), stp; | |
stp = .5 - .5*sin(7*t*f)*cos(5*t*f)*sin(3*t*f); | |
light.addColorStop(0, rgb_str); | |
light.addColorStop(stp, 'rgba(0,0,0,.03)'); | |
fillBackground('rgba(0,0,0,.02)'); | |
fillBackground(light); | |
t++; | |
if(t%T_SWITCH === 0) { | |
csi++; | |
if(csi === nwp) { | |
csi = 0; | |
t = 0; | |
} | |
} | |
request_id = requestAnimationFrame(neon); | |
}; | |
var fillBackground = function(bg_fill) { | |
ctx[0].fillStyle = bg_fill; | |
ctx[0].beginPath(); | |
ctx[0].rect(0, 0, w, h); | |
ctx[0].closePath(); | |
ctx[0].fill(); | |
}; | |
init(); | |
addEventListener('resize', init, false); | |
addEventListener('mousemove', function(e) { | |
source = { 'x': e.clientX, 'y': e.clientY }; | |
}, false); |
html, body, canvas { height: 100%; } | |
html { overflow: hidden; background: #020202; } | |
body { margin: 0; } | |
canvas { | |
position: absolute; | |
width: 100%; | |
} |