I'm trying to past multiple images on separate Canvas layers that are stacked upon each other yet the images aren't drawing on the canvas. Can someone help me out with what I am missing?
Thanks
CSS
.positionCanvas{
position: absolute;
left:0;
right:0;
margin-left:auto;
margin-right:auto;
background: rgba(255,255,255,0);
}
#logoCanvas{
position: relative;
}
HTML
<div id="logoCanvas">
<canvas class="positionCanvas" width="300" height="300" id="outerRingCanvas">
</canvas>
<canvas class="positionCanvas" width="300" height="300" id="crossCanvas">
</canvas>
<canvas class="positionCanvas" width="300" height="300" id="innerRingsCanvas">
</canvas>
<canvas class="positionCanvas" width="300" height="300" id="centreCanvas">
</canvas>
</div>
JAVASCRIPT
var outerRing = document.getElementById('outerRingCanvas'),
cross = document.getElementById('crossCanvas'),
innerRings = document.getElementById('innerRingsCanvas'),
centre = document.getElementById('centreCanvas');
var outerCtx = outerRing.getContext('2d'),
crossCtx = cross.getContext('2d'),
innerRingsCtx = innerRings.getContext('2d'),
centreCtx = centre.getContext('2d');
var ctxArray = [outerCtx, crossCtx, innerRingsCtx, centreCtx];
var outerImg = new Image(),
crossImg = new Image(),
innerRingsImg = new Image(),
centreImg = new Image();
var imgArray = [outerImg, crossImg, innerRingsImg, centreImg];
outerImg.src = "logo_ring.png";
crossImg.src = "logo_cross.png";
innerRingsImg.src = "logo_centre_rings.png";
centreImg.src = "logo_centre.png";
placeLogos(ctxArray);
crossCtx.drawImage(crossImg, 0, 0, 300, 300);
function placeLogos(array){
for(var i = 0; i < array.length; i++){
array[i].drawImage(imgArray[i], 100, 100, 100, 100);
array[i].fillStyle = "rgba(233,100,10,0.2)"
array[i].fillRect(0, 0, 300, 300);
}
}
Use the onload mechanism as image loading is asynchronous. If you're not using this the image may not be fully loaded when you try to use them leaving the canvas(es) blank.
...
var imageCount = 4;
outerImg.onload = loader;
crossImg.onload = loader;
innerRingsImg.onload = loader;
centreImg.onload = loader;
outerImg.src = "logo_ring.png";
crossImg.src = "logo_cross.png";
innerRingsImg.src = "logo_centre_rings.png";
centreImg.src = "logo_centre.png";
function loader() {
imageCount--;
if (imageCount === 0) {
placeLogos(ctxArray);
crossCtx.drawImage(crossImg, 0, 0, 300, 300);
}
}
Related
I have canvas with svg path on it. I want to do something like this:
http://jsfiddle.net/tbqrn/
var canvas = new fabric.Canvas('c');
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(10,10,150,150);
ctx.rect(180,10,200,200);
ctx.closePath();
ctx.stroke();
ctx.clip();
fabric.Image.fromURL(img01URL, function(oImg) {
oImg.scale(.25);
oImg.left = 50;
oImg.top = 100;
canvas.add(oImg);
canvas.renderAll();
});
fabric.Image.fromURL(img02URL, function(oImg) {
oImg.scale(.25);
oImg.left = 300;
oImg.top = 100;
canvas.add(oImg);
canvas.renderAll();
});
but with one difference: the image after leaving one area should immediately appear in another one.
How can I do it?
This is not doable with a single canvas. The only way I can think of that works is this:
Have two canvases with two different images and "synchronize" the position of the image between them. You actually have to use two images.
HTML:
<canvas id="c1" width="200" height="400"></canvas>
<canvas id="c2" width="200" height="400"></canvas>
CSS:
#c1, #c2 {
border: 1px solid #ccc;
}
#c2 {
margin-left: 20px;
}
.canvas-container {
float: left;
}
JS:
var offsetLeft = 220; // #c1 width + #c2 margin-left
var canvas1 = new fabric.Canvas('c1');
var canvas2 = new fabric.Canvas('c2');
var c1Img, c2Img;
fabric.Image.fromURL(img01URL, function(oImg) {
c1Img = oImg;
c1Img.scale(.25);
c1Img.left = 0;
c1Img.top = 0;
c1Img.hasControls = false;
c1Img.hasRotatingPoint = false;
canvas1.add(c1Img);
canvas1.renderAll();
});
fabric.Image.fromURL(img01URL, function(oImg) {
c2Img = oImg;
c2Img.scale(.25);
c2Img.left = -offsetLeft;
c2Img.top = 0;
c2Img.hasControls = false;
c2Img.hasRotatingPoint = false;
canvas2.add(c2Img);
canvas2.renderAll();
});
canvas1.on('object:moving', function(e) {
c2Img.set({left: e.target.left -offsetLeft, top: e.target.top});
c2Img.setCoords();
canvas2.renderAll();
});
canvas2.on('object:moving', function(e) {
c1Img.set({left: e.target.left + offsetLeft, top: e.target.top});
c1Img.setCoords();
canvas1.renderAll();
});
Test it here: http://jsfiddle.net/se9sw1d8/2/
Okay, I now tried to load two Kinetic images, but it still doesn't work. I also tried to put it on another layer and on another stage. Nothing helped. But with one image everything is fine.
var stage = new Kinetic.Stage({
container: 'container',
width: 1600,
height: 1000
});
var layer = new Kinetic.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var yoda = new Kinetic.Image({
x: 200,
y: 50,
image: imageObj,
width: 106,
height: 118
});
var imageObj2 = new Image();
imageObj2.onload = function() {
var vader = new Kinetic.Image({
x: 400,
y: 200,
image: imageObj2,
width: 206,
height: 218
});
// add the shape to the layer
layer.add(yoda);
layer.add(vader);
// add the layer to the stage
stage.add(layer);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';
imageObj2.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
OLD:
This is a sample code from http://www.html5canvastutorials.com/. I want to load two (or more) images and animate them both by clicking one button. Everything works fine with one picture, but this code confuses me. After the loadImages function is called there is no more reaction, even an alert isn't displayed. Where and how can I place my anim function?(I will implement the other animation later) Thanks for your ideas!
CSS
body {
margin: 0px;
padding: 0px;
}
#buttons {
position: absolute;
top: 50px;
left: 100px;
}
#buttons > input {
padding: 10px;
display: block;
margin-top: 5px;
}
HTML
<div id="container"></div>
<div id="buttons">
<input type="button" id="start" value="Start">
</div>
<canvas id="myCanvas" width="578" height="200"></canvas>
JS
document.getElementById('start').addEventListener('click', function() {
anim.start(); //button should start animation
}, false);
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, function(images) {
context.drawImage(images.darthVader, 100, 30, 200, 137);
context.drawImage(images.yoda, 150, 55, 93, 104);
});
var angularSpeed = 360 / 4; //from this line on it's like the js-code doesn't exist
var anim = new Kinetic.Animation(function(frame) { exist
var angleDiff = frame.timeDiff * angularSpeed / 1000;
images.yoda.rotate(angleDiff); //sources. instead images.?
}, layer);
You are mixing html5 canvas code with KineticJS library code.
You must create Kinetic.Image objects from each of your image objects.
Only then you can use Kinetic.Animation to animate them into rotation.
I'm using RaphaƫlJS for rotating an image forever. You can see the current result here. However, I'm experiencing some performance issues after resizing the browser window many times.
Could it be that new animations are created every time the window is resized while old ones are not removed? If that's the case, how can I stop and remove them? If not the case, any idea about how I could improve the performance?
The code is this:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
background-color: black;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
}
</style>
<script type="text/javascript" src="raphael.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var gearImageSrc = "images/gear.png";
var nikaImageSrc = "images/nika_half.png";
var logoImageSrc = "images/logo_mp.png";
var paper;
var gearImage = new Image();
var nikaImage = new Image();
var logoImage = new Image();
gearImage.src = gearImageSrc;
nikaImage.src = nikaImageSrc;
logoImage.src = logoImageSrc;
showAll = function () {
paper = Raphael(0, 0, canvas.width,canvas.height);
gear = paper.image(gearImageSrc, canvas.width/2 - gearImage.width/4, canvas.height/2 - gearImage.height/3, gearImage.width/2, gearImage.height/2);
nika = paper.image(nikaImageSrc, canvas.width/2 - nikaImage.width/4, canvas.height/2 - nikaImage.height/3, nikaImage.width/2, nikaImage.height/2);
logo = paper.image(logoImageSrc, canvas.width/2 - logoImage.width/4, canvas.height/2 + gearImage.height/6, logoImage.width/1.5, logoImage.height/1.5);
var spin = Raphael.animation({transform: "r-360"}, 10000).repeat(Infinity);
gear.animate(spin);
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
paper.remove();
showAll();
}
window.addEventListener('resize', resizeCanvas, false);
window.onload = function () {
showAll();
}
</script>
</body>
</html>
I might have a solution for it, just let me know if this works:
var spin = Raphael.animation({transform: "...r-360"}, 10000).repeat(Infinity);
You have to add ... in your transform() whenever you want to append to your transform, which you seem to be doing by re-sizing the window.
I want to join multiple canvases to make a single image.
So is there any method to covert more than one canvases to toDataURL to make a single image?
create a function that takes multiple arguments (canvas elements), puts them on one blank canvas, then returns the dataurl for the newly made canvas.
var getImadeData = function () {
var i = arguments.length,
tempCanvas = document.createElement("canvas"),
ctx = tempCanvas.getContext("2d");
while (i--) {
ctx.drawImage(arguments[i], 0, 0);
};
return tempCanvas.toDataURL();
};
Now just feed the function multiple canvas elements you want to put into one dataurl like so.
var newData = getImageData(canvas1, canvas2, canvas3);
In this example, the last canvas is placed on the blank canvas first so make sure to order your canvas elements appropriately.
Yes, the drawImage method on the canvas 2d rendering context accepts canvas elements as image elements. So all you have to do is:
Create a new canvas
Get its context
Draw all other canvases to it with drawImage
Extract the final image from this new canvas
try this example hope it will help see here
//html block
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;">
</canvas>
<canvas id="myCanvas1" width="200" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="Canvasimage" width="500" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<img id="finalimage" width="500" height="100" style="border:1px solid #c3c3c3;"/>
//script block
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function () {
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
window.onload = function (images) {
//Canvas first here
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 200, 100);
//Canvas second here
var c1 = document.getElementById("myCanvas1");
var ctx1 = c1.getContext("2d");
ctx1.fillStyle = "#00FF00";
ctx1.fillRect(0, 0, 200, 100);
//Canvas final here.
var canvas = document.getElementById("Canvasimage");
var context = canvas.getContext("2d");
var sources = {
darthVader: c.toDataURL("image/png"),
yoda: c1.toDataURL("image/png")
};
loadImages(sources, function (images) {
context.drawImage(images.darthVader, 100, 30, 200, 137);
context.drawImage(images.yoda, 350, 55, 93, 104);
//finalimage here which has two canvas data
var finalimage = document.getElementById("finalimage");
finalimage.src = canvas.toDataURL("image/png");
});
};
I have similar issue with layers as described here html5 - canvas element - Multiple layers
But, accepted answer doesn't work for me, as for layer1 I have rendered image (drawImage)
And second layer - layer2 (gradient) always under layer1.
Sample code:
canvas = document.getElementById("layer1");
ctx = canvas.getContext("2d");
var img = new Image();
img.src = "/img/img.png";
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
canvas2 = document.getElementById("layer2");
ctx2 = canvas.getContext("2d");
var my_gradient = ctx2.createLinearGradient(0, 0, 0, 400);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
ctx2.fillStyle = my_gradient;
ctx2.fillRect(0, 0, 500, 555);
HTML:
<canvas id="layer1" width="1000" height="1000" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
<canvas id="layer2" width="1000" height="1000" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
You are setting ctx2 to layer1's context:
ctx2 = canvas.getContext("2d");
Of course, since the image loads asynchronously, the onload event fires after you've already drawn the gradient, and it gets drawn on the same canvas.