D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tomgp
Full window
Github gist
canvas kaleidoscope
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>kaleidoscope</title> <style> body{ font-family: sans-serif; } .ui-label{ display: inline-block; width: 100px; } .state-ui{ max-width:500px; width:100%; } .input-value{ display: inline-block; width: 100px; } </style> </head> <body> <ul> <li> <span class="ui-label">offsetX</span> <input class="state-ui" data-targetprop="offsetX" type="range" min="0" max="1500"> <span data-targetprop="offsetX" class="input-value"></span> </li> <li> <span class="ui-label">offsetY</span> <input class="state-ui" data-targetprop="offsetY" type="range" min="0" max="3000"> <span data-targetprop="offsetY" class="input-value"></span> </li> <li> <span class="ui-label">offsetRotation</span> <input class="state-ui" data-targetprop="offsetRotation" type="range" min="0" max="6.28" step="0.001"> <span data-targetprop="offsetRotation" class="input-value"></span> </li> <li> <span class="ui-label">slices</span> <input class="state-ui" data-targetprop="slices" type="range" min="2" max="30" step="2"> <span data-targetprop="slices" class="input-value"></span> </li> <li> <span class="ui-label">zoom</span> <input class="state-ui" data-targetprop="zoom" type="range" min="0.01" max="2" step="0.01"> <span data-targetprop="zoom" class="input-value"></span> </li> </ul> <canvas></canvas> </body> <script> const HALF_PI = Math.PI/2; const TWO_PI = Math.PI*2; const state = { offsetRotation: 0.0, offsetScale: 1.0, offsetX: 0.0, offsetY: 0.0, radius: 300, slices: 8, //should be divisible by 2 zoom: 0.5, imageURL: 'https://assets.vogue.international.s3.amazonaws.com/projects/trends-2017/fullimages/oscar-de-la-renta-animales-fullsize.jpg' }; const canvas = document.querySelector('canvas'); canvas.width = state.radius * 2; canvas.height = state.radius * 2; const initUI = (props)=>{ Object.keys(props) .forEach((key)=>{ try{ document.querySelector('span[data-targetprop="'+key+'"]' ) .textContent = props[key]; document.querySelector('input[data-targetprop="'+key+'"]' ) .value = props[key]; }catch(e){ } }); } const draw = (props)=>{ const context = document.querySelector('canvas').getContext('2d'); context.fillStyle = context.createPattern(props.image, 'repeat'); const scale = props.zoom * (props.radius / Math.min(props.image.width, props.image.height)); const step = TWO_PI/state.slices; const cx = props.image.width/2; for(let i=0; i<props.slices; i++){ context.save(); context.translate(props.radius, props.radius); context.rotate(i * step) context.beginPath(); context.moveTo(-0.5, -0.5); context.arc( 0, 0, props.radius, step * -0.51, step * 0.51) context.lineTo(0.5, 0.5) context.closePath() context.rotate(HALF_PI) context.scale(scale, scale) context.scale([-1,1][i % 2], 1) context.translate(props.offsetX - cx, props.offsetY) context.rotate(props.offsetRotation) context.scale(props.offsetScale, props.offsetScale) context.fill() context.restore() } } initUI(state); var img = new Image(); state.image = img; img.onload = () => { draw(state); document.querySelectorAll('.state-ui') .forEach((node)=>{ node.oninput = (e)=>{ state[node.dataset.targetprop] = e.target.value; draw(state); document.querySelector('span[data-targetprop="'+node.dataset.targetprop+'"]' ) .textContent = e.target.value; }; }) }; img.src = state.imageURL; </script> </html>