Ricerca…
Effetto adesivo usando le ombre
Questo codice aggiunge esternamente ombre a un'immagine per creare una versione "adesiva" dell'immagine.
Gli appunti:
- Oltre ad essere un oggetto ImageObject, l'argomento "img" può anche essere un elemento Canvas. Ciò ti consente di auto-adesivizzare i tuoi disegni personalizzati. Se si disegna un testo sull'argomento Canvas, è anche possibile applicare un adesivo a tale testo.
- Le immagini completamente opache non avranno effetto adesivo perché l'effetto è disegnato attorno a gruppi di pixel opachi che sono bordati da pixel trasparenti.
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.style.background='navy';
canvas.style.border='1px solid red;';
// Always(!) wait for your images to fully load before trying to drawImage them!
var img=new Image();
img.onload=start;
// put your img.src here...
img.src='http://i.stack.imgur.com/bXaB6.png';
function start(){
ctx.drawImage(img,20,20);
var sticker=stickerEffect(img,5);
ctx.drawImage(sticker, 150,20);
}
function stickerEffect(img,grow){
var canvas1=document.createElement("canvas");
var ctx1=canvas1.getContext("2d");
var canvas2=document.createElement("canvas");
var ctx2=canvas2.getContext("2d");
canvas1.width=canvas2.width=img.width+grow*2;
canvas1.height=canvas2.height=img.height+grow*2;
ctx1.drawImage(img,grow,grow);
ctx2.shadowColor='white';
ctx2.shadowBlur=2;
for(var i=0;i<grow;i++){
ctx2.drawImage(canvas1,0,0);
ctx1.drawImage(canvas2,0,0);
}
ctx2.shadowColor='rgba(0,0,0,0)';
ctx2.drawImage(img,grow,grow);
return(canvas2);
}
Come smettere di ombreggiare ulteriormente
Una volta attivato lo shadowing, ogni nuovo disegno sulla tela verrà ombreggiato.
Disattiva ulteriormente l'ombreggiatura impostando context.shadowColor
su un colore trasparente.
// start shadowing
context.shadowColor='black';
... render some shadowed drawings ...
// turn off shadowing.
context.shadowColor='rgba(0,0,0,0)';
Shadowing è computazionalmente costoso - Cache that shadow!
Avvertimento! Applica le ombre con parsimonia!
Applicare lo shadowing è costoso ed è molto costoso se si applica lo shadowing all'interno di un ciclo di animazione.
Invece, memorizza nella cache una versione ombreggiata della tua immagine (o di un altro disegno):
All'inizio della tua app, crea una versione ombreggiata della tua immagine in un secondo Canvas in memoria:
var memoryCanvas = document.createElement('canvas') ...
Ogni volta che hai bisogno della versione in ombra, disegna l'immagine pre-ombreggiata dalla tela in memoria alla tela visibile:
context.drawImage(memoryCanvas,x,y)
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
canvas.style.border='1px solid red;';
document.body.appendChild(canvas);
// Always(!) use "img.onload" to give your image time to
// fully load before you try drawing it to the Canvas!
var img=new Image();
img.onload=start;
// Put your own img.src here
img.src="http://i.stack.imgur.com/hYFNe.png";
function start(){
ctx.drawImage(img,0,20);
var cached=cacheShadowedImage(img,'black',5,3,3);
for(var i=0;i<5;i++){
ctx.drawImage(cached,i*(img.width+10),80);
}
}
function cacheShadowedImage(img,shadowcolor,blur){
var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=img.width+blur*2+2;
c.height=img.height+blur*2+2;
cctx.shadowColor=shadowcolor;
cctx.shadowBlur=blur;
cctx.drawImage(img,blur+1,blur+1);
return(c);
}
Aggiungi profondità visiva con le ombre
L'uso tradizionale di shadowing è di dare ai disegni bidimensionali l'illusione della profondità 3D.
Questo esempio mostra lo stesso "pulsante" con e senza ombra
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
document.body.appendChild(canvas);
ctx.fillStyle='skyblue';
ctx.strokeStyle='lightgray';
ctx.lineWidth=5;
// without shadow
ctx.beginPath();
ctx.arc(60,60,30,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.stroke();
// with shadow
ctx.shadowColor='black';
ctx.shadowBlur=4;
ctx.shadowOffsetY=3;
ctx.beginPath();
ctx.arc(175,60,30,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.stroke();
// stop the shadowing
ctx.shadowColor='rgba(0,0,0,0)';
Ombre interne
Canvas non ha l' inner-shadow
del CSS.
- La tela ombreggia l'esterno di una forma piena.
- La tela ombreggia sia all'interno che all'esterno di una forma accarezzata.
Ma è facile creare ombre interne usando il compositing.
Colpi con un'ombra interiore
Per creare tratti con un'ombra interiore, utilizzare la composizione di destination-in
cui il contenuto esistente rimane solo dove il contenuto esistente viene sovrapposto al nuovo contenuto. I contenuti esistenti che non sono sovrapposti da nuovi contenuti vengono cancellati.
- Traccia una forma con un'ombra. L'ombra si estenderà sia verso l'esterno che verso l'interno dal tratto. Dobbiamo sbarazzarci dell'ombra esterna, lasciando solo l'ombra interiore desiderata.
- Imposta il compositing alla
destination-in
cui mantiene l'ombra tratteggiata esistente solo dove è sovrapposta a eventuali nuovi disegni. - Riempi la forma. Questo fa sì che il tratto e l'ombra interiore rimangano mentre l'ombra esterna viene cancellata. Bene, non esattamente! Poiché un tratto è metà dentro e metà all'esterno della forma piena, anche la metà esterna del tratto verrà cancellata. La correzione è raddoppiare il
context.lineWidth
modo che metà del tratto a doppia dimensione sia ancora all'interno della forma riempita.
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
document.body.appendChild(canvas);
// draw an opaque shape -- here we use a rounded rectangle
defineRoundedRect(30,30,100,75,10);
// set shadowing
ctx.shadowColor='black';
ctx.shadowBlur=10;
// stroke the shadowed rounded rectangle
ctx.lineWidth=4;
ctx.stroke();
// set compositing to erase everything outside the stroke
ctx.globalCompositeOperation='destination-in';
ctx.fill();
// always clean up -- set compsiting back to default
ctx.globalCompositeOperation='source-over';
function defineRoundedRect(x,y,width,height,radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
Riempie riempito con un'ombra interiore
Per creare riempimenti con un'ombra interiore, seguire i passaggi da 1 a 3 sopra, ma utilizzare ulteriormente destination-over
compositing di destination-over
che consente di disegnare nuovi contenuti sotto il contenuto esistente .
- Imposta il compositing su
destination-over
che fa disegnare il riempimento sotto l'ombra interna esistente. - Disattiva lo shadowing impostando
context.shadowColor
su un colore trasparente. - Riempi la forma con il colore desiderato. La forma sarà riempita sotto l'ombra interiore esistente.
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
document.body.appendChild(canvas);
// draw an opaque shape -- here we use a rounded rectangle
defineRoundedRect(30,30,100,75,10);
// set shadowing
ctx.shadowColor='black';
ctx.shadowBlur=10;
// stroke the shadowed rounded rectangle
ctx.lineWidth=4;
ctx.stroke();
// stop shadowing
ctx.shadowColor='rgba(0,0,0,0)';
// set compositing to erase everything outside the stroke
ctx.globalCompositeOperation='destination-in';
ctx.fill();
// set compositing to erase everything outside the stroke
ctx.globalCompositeOperation='destination-over';
ctx.fillStyle='gold';
ctx.fill();
// always clean up -- set compsiting back to default
ctx.globalCompositeOperation='source-over';
function defineRoundedRect(x,y,width,height,radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
Riempimenti non a tratti con un'ombra interiore
Per disegnare una forma piena con un'ombra interiore, ma senza tratto, puoi disegnare il tratto fuori campo e usare shadowOffsetX
per shadowOffsetX
l'ombra shadowOffsetX
di shadowOffsetX
.
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
document.body.appendChild(canvas);
// define an opaque shape -- here we use a rounded rectangle
defineRoundedRect(30-500,30,100,75,10);
// set shadowing
ctx.shadowColor='black';
ctx.shadowBlur=10;
ctx.shadowOffsetX=500;
// stroke the shadowed rounded rectangle
ctx.lineWidth=4;
ctx.stroke();
// stop shadowing
ctx.shadowColor='rgba(0,0,0,0)';
// redefine an opaque shape -- here we use a rounded rectangle
defineRoundedRect(30,30,100,75,10);
// set compositing to erase everything outside the stroke
ctx.globalCompositeOperation='destination-in';
ctx.fill();
// set compositing to erase everything outside the stroke
ctx.globalCompositeOperation='destination-over';
ctx.fillStyle='gold';
ctx.fill();
// always clean up -- set compsiting back to default
ctx.globalCompositeOperation='source-over';
function defineRoundedRect(x,y,width,height,radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}