Recherche…
Effet d'autocollant en utilisant des ombres
Ce code ajoute des ombres croissantes à une image pour créer une version "autocollant" de l'image.
Remarques:
- En plus d'être un objet ImageObject, l'argument "img" peut également être un élément Canvas. Cela vous permet de personnaliser vos propres dessins. Si vous dessinez du texte sur l'argument Canvas, vous pouvez également coller ce texte.
- Les images entièrement opaques n'auront aucun effet d'autocollant car l'effet est dessiné autour de groupes de pixels opaques bordés de pixels transparents.
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);
}
Comment arrêter d'autres ombres
Une fois que l'observation est activée, chaque nouveau dessin sur la toile sera ombré.
Désactivez d'autres masques en définissant context.shadowColor
sur une couleur transparente.
// start shadowing
context.shadowColor='black';
... render some shadowed drawings ...
// turn off shadowing.
context.shadowColor='rgba(0,0,0,0)';
L'observation est coûteuse en calculs - Cachez cette ombre!
Attention! Appliquez les ombres avec parcimonie!
Appliquer l'observation est coûteux et multiplicativement coûteux si vous appliquez l'observation dans une boucle d'animation.
Au lieu de cela, mettez en cache une version ombrée de votre image (ou un autre dessin):
Au début de votre application, créez une version ombrée de votre image dans un deuxième canevas en mémoire uniquement:
var memoryCanvas = document.createElement('canvas') ...
Chaque fois que vous avez besoin de la version ombrée, dessinez cette image pré-ombrée du canevas en mémoire dans le canevas visible:
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);
}
Ajouter de la profondeur visuelle avec des ombres
L'utilisation traditionnelle de l'ombrage consiste à donner des dessins bidimensionnels à l'illusion de la profondeur 3D.
Cet exemple montre le même "bouton" avec et sans ombrage
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)';
Ombres intérieures
Canvas n'a pas d' inner-shadow
CSS.
- La toile va masquer l'extérieur d'une forme remplie.
- La toile ira à la fois à l'intérieur et à l'extérieur d'une forme caressée.
Mais il est facile de créer des ombres intérieures en utilisant le compositing.
Coups avec une ombre intérieure
Pour créer des traits avec une ombre intérieure, utilisez destination-in
compositing qui provoque le contenu existant reste que si le contenu existant est chevauché par un nouveau contenu. Le contenu existant qui n'est pas recouvert par un nouveau contenu est effacé.
- Traitez une forme avec une ombre. L'ombre s'étendra à la fois vers l'extérieur et l'intérieur du trait. Nous devons nous débarrasser de l'ombre extérieure en ne laissant que l'ombre intérieure désirée.
- Définissez la composition à l’
destination-in
de ladestination-in
conserver l’ombre que si elle est recouverte par de nouveaux dessins. - Remplissez la forme. Cela fait que le trait et l'ombre intérieure restent pendant que l'ombre extérieure est effacée. Eh bien, pas exactement! Comme un trait est à mi-distance et à moitié en dehors de la forme remplie, la moitié extérieure de la course sera également effacée. La solution consiste à doubler le
context.lineWidth
afin que la moitié du trait double soit toujours dans la forme remplie.
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();
}
Filled Filled avec une ombre intérieure
Pour créer des remplissages avec une ombre interne, suivez les étapes 1 à 3 ci-dessus, mais utilisez davantage destination-over
composition par destination-over
ce qui entraîne la création de nouveaux contenus sous du contenu existant .
- Définissez la composition sur la
destination-over
ce qui entraîne le remplissage sous le masque interne existant. - Désactivez l'observation en définissant
context.shadowColor
sur une couleur transparente. - Remplissez la forme avec la couleur souhaitée. La forme sera remplie sous l'ombre interne existante.
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();
}
Remplissage sans traits avec une ombre intérieure
Pour dessiner une forme remplie avec une ombre interne, mais sans le moindre trait, vous pouvez dessiner le trait hors-toile et utiliser shadowOffsetX
pour repousser l'ombre sur le canevas.
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();
}