I found this code
http://jsfiddle.net/dtrooper/AceJJ/
and I'm trying to add a background image to the canvas (so it won't be black).
I've added these lines to the $(document).ready function
var background = new Image();
background.src = url("img/header.jpg");
But all I get is Uncaught SyntaxError: Unexpected token ILLEGAL
I also want to have text on top of the background (saying something like "Welcome to the new year" + NewLine + "Be safe and good luck"
Thank You
In the loop function change this:
// clear canvas
context.fillStyle = "rgba(0, 0, 0, 0.05)";
context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
To this:
context.save();
if (first) { // only the first time you draw the full image
first = false;
context.globalAlpha = 1;
} else {
context.globalAlpha = 0.2; // <--- PLAY WITH THIS FOR BETTER EFFECT
}
context.drawImage(img, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
context.restore()
// clear canvas
//context.fillStyle = "rgba(0, 0, 0, 0.05)";
//context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
And out of the loop function add this:
var img = new Image();
var first = true;
img.src = "YOUR_IMAGE_URL";
Is not perfect, but from here you can find your solution.
The example:
http://jsfiddle.net/AceJJ/1748/
jsFiddle : https://jsfiddle.net/CanvasCode/6ju8acro/1/
javascript
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = new Image();
img.src = "http://imagesci.com/img/2013/03/cute-christmas-dogs-8313-hd-wallpapers.jpg";
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.font = '40pt Calibri';
ctx.fillStyle = 'red';
ctx.fillText("Welcome to the new year", 250, 100);
ctx.fillText("Be safe and good luck", 350, 600);
}
You have to create a new Image variable and then access its property src which is the source of the image. So you first create a new Image provide a source. Then we must first wait for the image to load. Once the image has loaded we render it to the canvas via drawImage, then we go ahead and draw some text using the fillText function.
You will have to work out how to centre the text correctly and change the image but the code I have provided should get you started :)
Updated
jsFiddle : http://jsfiddle.net/CanvasCode/AceJJ/1743/
// clear canvas
// Render background and text first
context.drawImage(img, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
context.font = '40pt Calibri';
context.fillStyle = 'red';
context.fillText("Welcome to the new year", 150, 100);
context.fillText("Be safe and good luck", 250, 600);
//context.fillStyle = "rgba(0, 0, 0, 0.05)";
//context.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
Just render the image and text in the loop function, however as I stated above you will need to work out the best way to render the image and text
Another Update
jsFiddle : http://jsfiddle.net/CanvasCode/AceJJ/1756/
To draw the firework trails over the image, just create particles when the rocket is rendered like so
// ... near the end of the Rocket.prototype.render function
c.fill();
c.restore();
var particle = new Particle(this.pos);
particle.size = 10;
particle.gravity = 0.2;
particle.resistance = 0.92;
particle.shrink = Math.random() * 0.05 + 0.93;
particle.flick = true;
particle.color = this.explosionColor;
particles.push(particle);
};
Try this :
var img = new Image();
img.src = "http://imgurl.com";
url() is used in CSS.
Related
In a html canvas, I am trying to generate a drop shadow on an image with transparent pieces in it. This image is generated by code and then drawn to the canvas using: ctx.putImageData(dst, 0, 0)
The problem is that the following code is not generating any shadow:
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 15;
ctx.shadowColor = 'rgba(0,0,0,1)';
ctx.putImageData(dst, 0, 0);
Any help would be appreciated
ctx.putImageData() will replace the pixels in your context with the ones contained in the ImageData that you puts.
There is no context's property like shadowBlur, nor filter, nor globalCompositeOperation, nor even matrix tranforms that will affect it. Even transparent pixels in your ImageData will be transparent in the context.
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'salmon';
ctx.fillRect(0,0,300,150);
ctx.translate(120, 50);
ctx.rotate(Math.PI/3);
ctx.translate(-25, -25);
ctx.filter = 'blur(5px)';
ctx.globalCompositeOperation = 'lighter';
ctx.fillStyle = '#0000FF';
ctx.fillRect(0,0,50,50);
setTimeout(() => {
// at this time, all previous filters, transform, gCO are still active
const bluerect = ctx.createImageData(50,50);
const data = new Uint32Array(bluerect.data.buffer);
data.fill(0xFFFF0000); // blue
ctx.putImageData(bluerect, 0, 0); // same as our previous fillRect();
// a transparent ImageData (smaller)
const transrect = ctx.createImageData(25, 25);
ctx.putImageData(transrect, 170, 50); // push a bit farther;
}, 1500);
body {
background: lightblue;
}
<canvas id="canvas"></canvas>
So, how to deal with an ImageData and still be able to apply the context's properties on it?
Go through a second off-screen canvas, on which you will put your ImageData, and that you will then draw on your main canvas. drawImage accepts an HTMLCanvasElement as source, and it is affected by context properties like shadowBlur:
const ctx = canvas.getContext('2d');
ctx.shadowBlur = 12;
ctx.shadowColor = "red";
// our ImageData
const bluerect = ctx.createImageData(50,50);
const data = new Uint32Array(bluerect.data.buffer);
data.fill(0xFFFF0000); // blue
// create a new canvas, the size of our ImageData
const offscreen = document.createElement('canvas');
offscreen.width = bluerect.width;
offscreen.height = bluerect.height;
// put our ImageData on it
offscreen.getContext('2d')
.putImageData(bluerect, 0, 0);
// draw it on main canvas
ctx.drawImage(offscreen, 50, 50);
<canvas id="canvas"></canvas>
Now, new browsers have also the ability to do it without the use of a second browser, by generating an ImageBitmap from the ImageData, but this operation is asynchronous, so you may still prefer the old way.
const ctx = canvas.getContext('2d');
ctx.shadowBlur = 12;
ctx.shadowColor = "red";
// our ImageData
const bluerect = ctx.createImageData(50,50);
const data = new Uint32Array(bluerect.data.buffer);
data.fill(0xFFFF0000); // blue
// create an ImageBitmap from our ImageData
createImageBitmap(bluerect)
.then(bitmap => { // later
ctx.drawImage(bitmap, 50, 50);
});
<canvas id="canvas"></canvas>
I have come up with something that suits my needs based on the threads on this subject.
It turns out that in order to scale an image for pattern fill you need 2 canvases. The first canvas creates the scaled image which is used in the second canvas. All of the examples I found display both canvases, but I only want to display the second canvas
Snip:
var c = document.getElementById("DrawQuote");
var ctx = c.getContext("2d");
ctx.clearRect(10, 10, c.width, c.height);
Then ctx context is used to draw some rectangles and polygons, I omitted the code
Then I need to draw a rectangle with scaled image pattern
Snip:
// create the canvas with scaled image
var imgtoscale = new Image();
imgtoscale.src = "blah.jpg";
var canvas1 = document.getElementById("TempCanvas");
var ctx1 = canvas1.getContext("2d");
canvas1.width = imgtoscale.width / Scale / 4;
canvas1.height = imgtoscale.height / Scale / 4;
ctx1.drawImage(imgtoscale, 0, 0, canvas1.width, canvas1.height);
// draw a rectangle filled with the scaled image from above
// ctx is my main canvas, the one I want to display
ctx.fillStyle = ctx.createPattern(canvas1, "repeat");
ctx.fillRect(400, 40, 300, 300);
2 images are displayed:
1-the scaled image to the TempCanvas element
2-the rectangle with scaled fill pattern to the DrawQuote element
But I only want to display the DrawQuote element
Not sure what "threads" you saw, but I guess they were displaying the second canvas only to make clear what happens, however, you really don't need to append that second canvas in the document, it can stay "offscreen":
// the only one visible
var canvas = document.getElementById( 'canvas' );
var ctx = canvas.getContext( '2d' );
var Scale = 2;
var imgtoscale = new Image();
imgtoscale.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/Woodward_Iowa_Tornado_Damage.JPG/1024px-Woodward_Iowa_Tornado_Damage.JPG";
imgtoscale.onload = function() {
// we create a new canvas element
var canvas1 = document.createElement( 'canvas' );
var ctx1 = canvas1.getContext( '2d' );
canvas1.width = imgtoscale.width / Scale / 4;
canvas1.height = imgtoscale.height / Scale / 4;
ctx1.drawImage( imgtoscale, 0, 0, canvas1.width, canvas1.height );
// draw a rectangle filled with the scaled image from above
// ctx is my main canvas, the one I want to display
ctx.fillStyle = ctx.createPattern( canvas1, 'repeat' );
ctx.fillRect( 100, 100, 300, 300 );
};
canvas { border: 1px solid }
<canvas id="canvas" width="500" height="500"></canvas>
Now note that what these threads missed is that the fillStyle is dependent on the current transformation matrix of the context, so you don't even need a second canvas to do what you want:
First declare the path you wish to fill at normal scale, then set the context scale to what you want, and finally fill.
// the only canvas
var canvas = document.getElementById( 'canvas' );
var ctx = canvas.getContext( '2d' );
var Scale = 2;
var imgtoscale = new Image();
imgtoscale.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/04/Woodward_Iowa_Tornado_Damage.JPG/1024px-Woodward_Iowa_Tornado_Damage.JPG";
imgtoscale.onload = function() {
// create the CanvasPattern directly from the <img>
ctx.fillStyle = ctx.createPattern( imgtoscale, 'repeat' );
// declare your path to fill
ctx.beginPath();
ctx.rect( 100, 100, 300, 300 );
// change the scaling (of the fillStyle)
ctx.scale( 1 / Scale / 4, 1 / Scale / 4 );
ctx.fill();
// reset back to default?
ctx.setTransform( 1, 0, 0, 1, 0, 0 );
};
canvas { border: 1px solid }
<canvas id="canvas" width="500" height="500"></canvas>
I'm trying to place text over a background color. I think the issue is that the "fillStyle" is being applied to both the text and the background. I want the text to be black. What am I doing wrong here?
Below is my code:
var canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
var ctx = canvas.getContext("2d");
ctx.fillText("hello", 0, 0);
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
var img = document.createElement("img");
img.src = canvas.toDataURL("image/png");
document.body.appendChild(img);
Here's a link to the fiddle: https://jsfiddle.net/jessecookedesign/9rsy9gjn/36/
Unlike HTML where you define a list of what you want to appear, when working with a canvas it's like you're painting. So each "drawing" operation you do (like fillRect or fillText) will go on top of any existing content and cover it up.
Similarly since you're actually painting, rather than defining objects, you need to set the fill style before drawing. Using the analogy, you need to select the color of paint you'll use before you put paint to canvas.
Finally, the fillText method takes a position as the start of the baseline of the text. Since (0, 0) is the top left of the canvas, your text will get drawn above the bounds of the canvas an not be visible, so you need to move it down e.g. fillText("Hello World", 10, 100);
Correcting for those issues you get something like the following (and skipping the steps involved in converting to an img tag):
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Draw a black background
context.fillStyle = "black";
context.fillRect(0, 0, 200, 200);
// Draw the text
context.fillStyle = "#E7E0CA";
context.fillText("Hello world", 10, 100);
<canvas id="canvas" width="200" height="200"></canvas>
Wrong order - You're drawing the rectangle over the text.
The text has the same color as the rectangle
There's no font specified
The position (0,0) is out of bounds
Try it like this:
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText("hello",10,30);
There are several issues:
You need to first fill the background, then fill the text.
Your text is above the canvas area — try a lower position.
This code has the correct order, and a position for the text that isn’t outside the canvas bounds.
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = "#000000";
ctx.fillText("hello", 10, 10);
With the changed order, of course you need to choose a new color for the text, in this case "#000000".
Alternatively, you could save and restore your canvas state:
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "#E7E0CA";
ctx.fillRect(0, 0, 200, 200);
ctx.restore();
ctx.fillText("hello", 10, 10);
Whenever you access canvas of html page,
whatever you draw first, will display first.
so if you want to display your colored box first fill it first, then write your text by providing color ,font and position of text. for example,
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#E7E0CA";//your rect color
ctx.fillRect(0, 0, 200, 200);//your rect size
ctx.fillStyle = "#000000";//color for your text
ctx.font="30px Arial";//font style and size
ctx.fillText("hello world",25,50);//text and location
</script>
I am new to canvas, I have an image myimg.jpg, I have converted this image into canvas and i am trying to apply some pattern image for heel.
I am not able to do it. Here is my screenshot:
How can I get it done.
<div id="myId">
<canvas id="canvaswrapper" width="660" height="540"></canvas>
</div>
function drawImage(){
var ctx = $("canvas")[0].getContext("2d"),
img = new Image();
img.onload = function(){
ctx.drawImage(img, 0, 0, 500, 500);
ctx.beginPath();
var img2= new Image();
var w;
var h;
img2.src = "http://www.gravatar.com/avatar/e555bd971bc2f4910893cd5b785c30ff?s=128&d=identicon&r=PG";
var pattern = ctx.createPattern(img2, "repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, w, h);
ctx.arc(300,305,50,0,2*Math.PI);
ctx.fill();
ctx.stroke();
};
img.src = "myimg.jpg";
}
drawImage();
You can define the area you want to fill using an image mask that fits on top of your image - this step is something for Photoshop/GIMP.
For example, having your shoe as-is:
Create a mask for it leaving the heal in the original position (it makes it easier to draw it back in - you can always crop it and draw it using an offset instead). Important: background must be transparent:
Then super-impose the pattern using these steps:
Load the pattern and define is as a fill-pattern
Draw the mask into the empty canvas
Optional step: Adjust transformations if needed (translate, scale)
Choose composite mode "source-atop"
Fill the canvas
Choose composite mode "destination-atop"
Draw the main image on top (which will show behind the mask/pattern)
Optional step: draw in original mask image using blending mode "multiply" to add shadow and highlights (does not work in IE). This will help creating an illusion of depth. For IE, drawing it on top using a reduced alpha or a separate image only containing shadows etc. can be an option
Result
Example
var iShoe = new Image, iMask = new Image, iPatt = new Image, count = 3;
iShoe.onload = iMask.onload = iPatt.onload = loader;
iShoe.src = "http://i.stack.imgur.com/hqL1C.png";
iMask.src = "http://i.stack.imgur.com/k5XWN.png";
iPatt.src = "http://i.stack.imgur.com/CEQ10.png";
function loader() {
if (--count) return; // wait until all images has loaded
var ctx = document.querySelector("canvas").getContext("2d"),
pattern = ctx.createPattern(iPatt, "repeat");
// draw in mask
ctx.drawImage(iMask, 0, 0);
// change comp mode
ctx.globalCompositeOperation = "source-atop";
// fill mask
ctx.scale(0.5, 0.5); // scale: 0.5
ctx.fillStyle = pattern; // remember to double the area to fill:
ctx.fillRect(0, 0, ctx.canvas.width*2, ctx.canvas.height*2);
ctx.setTransform(1,0,0,1,0,0); // reset transform
// draw shoe behind mask
ctx.globalCompositeOperation = "destination-atop";
ctx.drawImage(iShoe, 0, 0);
// to make it more realistic, add mask in blend mode (does not work in IE):
ctx.globalCompositeOperation = "multiply";
if (ctx.globalCompositeOperation === "multiply") {
ctx.drawImage(iMask, 0, 0);
}
}
<canvas width=281 height=340></canvas>
I've been following the lessons about transparency and gradients on the Mozilla site: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Applying_styles_and_colors but I have not been able to figure this one out.
I know I can achieve these effects with a png image; however, in the program I am working on the gradient will change constantly according to where the image is moved.
Here's an example of the effect I'm looking for.
http://home.insightbb.com/~epyonxl1/gradientex.jpg
Its possible to use context.globalCompositeOperation to make the the mask
context.drawImage(img, 0, 0, img.width, img.height, 0,0, img.width, img.height);
context.globalCompositeOperation = "destination-out";
gradient = context.createLinearGradient(0, 0, 0, img.height);
gradient.addColorStop(0, "rgba(255, 255, 255, 0.5)");
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
context.fillStyle = gradient;
context.fillRect(0, 0, img.width, img.height);
This do not do per pixel manipulation and should be faster
To correctly merge two images using a transparency mask it's first necessary to take one of the two images and put it into an off screen canvas, and add the desired transparency mask using context.globalCompositeOperation = destination-out per #Tommyka's answer
var offscreen = document.createElement('canvas'); // detached from DOM
var context = offscreen.getContext('2d');
context.drawImage(image1, 0, 0, image1.width, image1.height);
var gradient = context.createLinearGradient(0, 0, 0, img.height);
gradient.addColorStop(0, "rgba(255, 255, 255, 0.5)");
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
context.globalCompositeOperation = "destination-out";
context.fillStyle = gradient;
context.fillRect(0, 0, image1.width, image1.height);
Then, to actually merge the two images you then need to draw the other image into another canvas, and then simply draw the alpha-composited offscreen canvas on top of that:
var onscreen = document.getElementById('mycanvas');
var context2 = onscreen.getContext('2d');
context2.drawImage(image2, 0, 0, image2.width, image2.height);
context2.drawImage(offscreen, 0, 0, onscreen.width, onscreen.height);
Demo at http://jsfiddle.net/alnitak/rfdjoh31/4/
I've aded some code here: https://code.google.com/archive/p/canvasimagegradient/ that adds a drawImageGradient function to the CanvasRenderingContext2D. You can draw an image with a linear or radial gradient. It doesn't work in IE, even with excanvas, due to the lack of getImageData/putImageData support.
The following code for example will draw an image with a radial gradient (context retrieve and image load not shown):
var radGrad = ctx.createRadialGradient(
img.width / 2, img.height / 2, 10,
img.width / 2, img.height / 2, img.width/2);
radGrad.addColorStop(0, "transparent");
radGrad.addColorStop(1, "#000");
ctx.drawImageGradient(img, 112.5, 130, radGrad);
The code works as follows:
Create a canvas element dynamically and draw the image on it.
Retrieve the imageData for this new canvas.
Retrieve the imageData for the location on the canvas you want to draw the image on to.
Iterate through the destination imageData and update each pixel adding together a percentage (derived from the gradient transparency value) of the image and destination pixel values.
Finally put the updated image data back onto the destination canvas.
Obviously performance is an issue as images get larger. The image on https://code.google.com/archive/p/canvasimagegradient/ it takes about 6-10ms to draw. A 1024x768 image takes about 100ms-250ms to draw. Still usable though as long as you're not animating.
If you need to make an image transparent set the ctx.globalAlpha to whatever you need (1, no transparency, is default). Then reset it after you draw your image. This URL probably will help as well https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Compositing.
I have modernized Alnitak's response by incorporating asynchronous loading of the images.
I also got rid of magic numbers.
const imageUrls = [
// Base image
'http://www.netstate.com/states/symb/flowers/images/apple_blossoms.jpg',
// Gradient image
'http://www.netstate.com/states/symb/flowers/images/oklahoma_rose.jpg'
];
const main = async () => {
const ctx = document.getElementById('cv').getContext('2d'),
baseImg = await loadImage(imageUrls[0]),
gradImg = await loadImage(imageUrls[1]);
draw(ctx, baseImg, gradImg);
};
/**
* Loads an Image object via a Promise.
* #param {String} url - Location of an image file
* #return {Promise<Image>} Returns a promise that resolves to an Image.
*/
const loadImage = (url) => new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', reject);
img.src = url;
});
/**
* Draws an image, as a gradient applied to it, above another image.
* #param {Image} baseImg - Image that is applied under the gradient
* #param {Image} gradImg - Image to be applied as a gradient
*/
const draw = (ctx, baseImg, gradImg) => {
const {width, height} = baseImg,
originX = Math.floor(width / 2),
originY = Math.floor(height / 2),
radius = Math.min(originX, originY);
const offScreen = document.createElement('canvas');
offScreen.width = offScreen.height = width;
const ctx2 = offScreen.getContext('2d');
ctx2.drawImage(gradImg, 0, 0, width, height);
const gradient = ctx2.createRadialGradient(originX, originY, 0, originX, originY, radius);
gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 1)');
ctx2.fillStyle = gradient;
ctx2.globalCompositeOperation = 'destination-out';
ctx2.fillRect(0, 0, width, height);
ctx.drawImage(baseImg, 0, 0, width, height);
ctx.drawImage(offScreen, 0, 0, width, height);
};
main();
<canvas id="cv" width="300" height="300"></canvas>