Il grande Chris Heilmann (codepo8 su Twitter) riesce ancora una volta a stupirci con la sua capacità di creare in maniera semplice e intuitiva dei "trucchi" HTML5 che ci dimostrano quali grandi possibilità questa nuova tecnologia ci offre.

Oggi vedremo come in poche righe di codice è possibile creare un effetto di "ombra" per qualunque oggetto e disegno noi vogliamo realizzare su canvas

L'intero "esperimento" è presente su jsFiddle all'indirizzo http://jsfiddle.net/codepo8/eUYKu/ ma noi vi riportiamo qui il codice intero per comodità:

/*<br />      Shadow with blur simulation<br />      hacked together by Chris Heilmann (@codepo8)<br />    */<br />    <br />    var container = document.createElement( 'ul' );<br />    document.body.appendChild( container );<br />    <br />    var canvas = document.createElement( 'canvas' );<br />    document.body.appendChild( canvas );<br />    <br />    c = canvas.getContext( '2d' );<br />    canvas.width = 400;<br />    canvas.height = 400;<br />    c.strokeStyle = "#000";<br />    c.lineWidth = 2;<br />    <br />    var mouseX = 0,<br />        mouseY = 0,<br />        hw = canvas.width / 2,<br />        hh = canvas.height / 2,<br />        shadowmultiplier = 0.4;<br />    <br />    canvas.addEventListener( 'mousemove', function( event) {<br />      if(event.offsetX){<br />        mouseX = event.offsetX;<br />        mouseY = event.offsetY;<br />      } else {<br />        mouseX = event.pageX - event.target.offsetLeft;<br />        mouseY = event.pageY - event.target.offsetTop;<br />      }<br />      draw();<br />    }, false );<br />    <br />    function draw() {<br />      c.clearRect(0,0,canvas.width, canvas.height);<br />      drawline(c);<br />    }<br />    <br />    function drawline(c){<br />    <br />      var distx = (mouseX-hw),<br />          disty = (mouseY-hh),<br />          realdistance = Math.sqrt( ( distx * distx ) + ( disty * disty ) ),<br />          blur = Math.round( realdistance / ( hw / 8 ) );<br />    <br />      container.innerHTML = ''+<br />        '<li>mouse-x: ' + mouseX + '</li>'+<br />        '<li>mouse-y: ' + mouseY + '</li>'+<br />        '<li>centred-x: ' + distx + '</li>'+<br />        '<li>centred-y: ' + disty + '</li>'+<br />        '<li>distance: ' + todec(realdistance) + '</li>'+<br />        '<li>shadow-x: ' + todec(-(distx * shadowmultiplier)) + '</li>'+<br />        '<li>shadow-y: ' + todec(-(disty * shadowmultiplier)) + '</li>'+<br />        '<li>blur: ' + blur + '</li>';<br />    <br />      c.save();<br />    <br />      // line to show distance<br />      c.translate(hw,hh);<br />      c.beginPath();<br />      c.strokeStyle = "rgba(0,0,0,0.3)";<br />      c.lineWidth = 2;<br />      c.moveTo(0,0);<br />      c.lineTo(distx,disty);<br />      c.closePath();<br />      c.stroke();<br />    <br />      // shadow line<br />      c.beginPath();<br />      c.strokeStyle = "rgba(128,0,0,0.3)";<br />      c.lineWidth = 2;<br />      c.moveTo(0,0);<br />      c.lineTo( -distx * shadowmultiplier, -disty * shadowmultiplier );<br />      c.closePath();<br />      c.stroke();<br />      <br />      // sun<br />      c.fillStyle = 'yellow';<br />      c.beginPath();<br />      c.arc( distx, disty , 30, 0, Math.PI*2, true );<br />      c.closePath();<br />      c.fill();<br />    <br />      // eyes<br />      c.fillStyle = '#000';<br />      c.beginPath();<br />      c.arc( distx - 12, disty - 8 , 4, 0, Math.PI*2, true );<br />      c.arc( distx + 12, disty - 8 , 4, 0, Math.PI*2, true );<br />      c.closePath();<br />      c.fill();<br />    <br />      // smile<br />      c.strokeStyle = '#000';<br />      c.beginPath();<br />      c.arc( distx, disty , 20, 0.4, Math.PI-0.4, false );<br />      c.stroke();<br />      c.restore();<br />    <br />      // shape and shadow<br />      c.save();<br />      c.fillStyle = "#000";<br />      c.shadowOffsetX = -distx * shadowmultiplier;<br />      c.shadowOffsetY = -disty * shadowmultiplier;<br />      c.shadowBlur = blur;<br />      c.shadowColor = 'rgba(0,0,0, 0.5)';<br />      c.translate( hw+20, hh );<br />      c.rotate( 135 * ( Math.PI / 180 ) );<br />      c.beginPath();<br />      c.moveTo(0,0);<br />      c.lineTo(50,0);<br />      c.lineTo(50,20);<br />      c.lineTo(20,20);<br />      c.lineTo(20,50);<br />      c.lineTo(0,50);<br />      c.closePath();<br />      c.fill();<br />      c.restore();<br />    <br />    }<br />    <br />    function todec(num){<br />     return Math.round(num*100)/100;<br />    }<br />

Uno dei punti di base è:

  c.shadowOffsetX = -distx * shadowmultiplier;<br />      c.shadowOffsetY = -disty * shadowmultiplier;<br />      c.shadowBlur = blur;<br />      c.shadowColor = 'rgba(0,0,0, 0.5)';

Qui vengono specificati i paramentri della "shadow" (ombra) indicandone la distanza (X e Y) dal disegno principale, il colore (nero con il 50% di opacità) e la sfocatura (che viene calcolata dinamicamente a seconda della distanza). Questo è il "cuore" delle ombre in canvas – tutto il resto è per lo più funzionale al funzionamento del "trucco", cioè alla faccina e al fatto che l'ombra cambi al muovere del mouse.