canvas: bind photo into the frame - javascript

Good day!
I have a problem with merging canvas images. This questions will be mark as reply I think but I didn't find solution for my problem.
So this the deal:
Get 3 canvas - 1 and 2 are images(must be hidden i think), 3 - merged canvas. 1 is a frame, 2 is a photo, photo must be under frame (at css I could make it with z-index).
Html:
<div class="container">
<canvas id="first" width="400" height="400"></canvas>
<canvas id="second" width="200" height="200"></canvas>
<canvas id="third" width="400" height="400"></canvas>
</div>
JS:
var imgFirst = document.getElementById("first");
ctx1 = imgFirst.getContext('2d');
pic1 = new Image();
pic1.src = "http://www.deftune.com/wp-content/uploads/2010/10/thexx-400x400.jpg";
var imgSecond = document.getElementById("second");
ctx2 = imgSecond.getContext('2d');
pic2 = new Image();
pic2.src = "http://tech21info.com/admin/wp-content/uploads/2013/03/chrome-logo-200x200.png";
var imgThird = document.getElementById('third');
ctx3 = imgThird.getContext('2d');
pic1.onload = function() {
pic2.onload = function() {
ctx3.drawImage(pic1, 0, 0, 400, 400);
ctx3.drawImage(pic2, 100, 100, 200, 200);
};
};
I've got jsfiddle example: http://jsfiddle.net/hh6ovneq/3/ but it not works

There are a couple of things that could simplify your code a lot. First of, since you are only loading image resources, use the img tag instead. Then create a callback function and trigger it when both images have loaded.
Since I am unclear what your photo is and what your frame is I currently use the inversed order that you had, but just switching the two drawImage functions should switch their order (or z-index, hopwever you want to describe it). Because your top image doesn't have transparent values, though, it will hide the bottom image as the pixels are overwritten with new colors.
The result would look something like this, which looks a lot cleaner and more readable:
// Get all your images.
var first = document.getElementById('first');
var second = document.getElementById('second');
// get canvas and context
var result = document.getElementById('result');
var context = result.getContext('2d');
// create a counter to make sure all images are loaded before drawing
var loaded = 0;
// something to execute when loading of images has completed
function combine(){
// The order of drawing will be the order of layers
// The final two arguments define the size of what you want to draw
context.drawImage(second, 0, 0, 400, 400);
context.drawImage(first, 100, 100, 200, 200);
}
// Add event listeners to the images
first.addEventListener('load', function(){
// increase the loaded number
loaded++;
// hide the image
first.style.display = 'none';
// if loaded hits the total number of images, use the completion function
if(loaded === 2) combine();
}, false);
// (wrince, repeat for image 2)
second.addEventListener('load', function(){
loaded++;
second.style.display = 'none';
if(loaded === 2) combine();
}, false);
<div class="container">
<img id="first" width="400" height="400" src="http://www.deftune.com/wp-content/uploads/2010/10/thexx-400x400.jpg" />
<img id="second" width="200" height="200" src="http://tech21info.com/admin/wp-content/uploads/2013/03/chrome-logo-200x200.png" />
<canvas id="result" width="400" height="400"></canvas>
</div>
Lastly I would like to add that your nested onload function could backfire on you when the second image is loaded before the first, which would mean that the load event does not get triggered anymore. Use separate onloads and count them in order to be sure the outcome is correct.

Related

A-Frame/Javascript-Slideshow has wrong mapping

I have a similar slideshow displayed a few times here! It works fine but I don't get the right mapping on an a-sky. I am not a coder but I guess drawImage is just made for rectangular objects instead of spherical? Is there an alternative to drawImage which works for spherical?
Here are my codes:
AFRAME.registerComponent('draw-canvas', {
schema: {
type: 'selector'
},
init: function() {
var canvas = this.canvas = this.data;
var ctx = this.ctx = canvas.getContext('2d');
var i = 0; // Start Point
var images = []; // Images Array
var time = 3000; // Time Between Switch
// Image List
images[0] = "Tulips.jpg";
images[1] = "Tulips2.jpg";
images[2] = "Tulips3.jpg";
// Change Image
function changeImg() {
document.getElementById('pic01').src = images[i];
ctx.drawImage(document.getElementById('pic01'), 0, 0, 300, 300);
// Check If Index Is Under Max
if (i < images.length - 1) {
// Add 1 to Index
i++;
} else {
// Reset Back To O
i = 0;
}
// Run function every x seconds
setTimeout(function() {
changeImg()
}, time);
}
// Run function when page loads
window.onload = changeImg;
console.log("Hello World!");
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Canvas Texture</title>
<meta name="description" content="Canvas Texture - A-Frame">
<script src="./components/aframe-v0.6.0.js"></script>
<script src="./components/slideshow.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<img id="pic01" src="Tulips.jpg">
<img id="pic02" src="Tulips2.jpg">
<img id="pic03" src="Tulips3.jpg">
<canvas id="slide" name="slide" crossOrigin="anonymous"> </canvas>
</a-assets>
<a-sky material="shader: flat; src: #slide" draw-canvas="#slide">
<a-sky/>
</a-scene>
</body>
</html>
And if anybody knows how to nicely fade over the pictures, please feel free to share! I bet a lot of people would be happy about a nice A-Frame Slideshow.
I've got a solution, but I've altered quite a lot of Your stuff.
I've got rid of the canvas, You already have three image assets, no need to rewrite, or buffer them on each other.
Just store the asset id's and use setAttribute("material", "src", picID)
Furthermore I've added the a-animation component, so Your slideshow will have a nice smooth transition. You need to set the animation duration to the slideshow's time / 2, for it goes back and forth.
This said, check out my fiddle.
As for the drawImage part of the question, drawImage draws (writes) an image onto a canvas element. The mapping is fine, since You only need to make sure You have a spherical photo, otherwise it will get stretched all over the model.

How to overlay Canvas with a Canvas dynamically?

i have a canvas dynamically written with no id assigned to it. How can i overlay image on the first canvas (out of multiple canvas) via JS ?
<canvas width="240" height="297">
<canvas id = "image_to_Overlay" width = "800" height = "500"></canvas>
In order to get the 1st canvas of the DOM using plain javascript you can use the good old function document.getElementsByTagName(). Then do what you want with it.
Probably it would be safer matching even on other attributes - such as class name - just to avoid getting the wrong canvas (jquery selectors would work great).
BTW the following should work
<html>
<head>
<script>
var image = new Image();
image.onload = function (){//react on image download completed
//you can get the 1st canvas of the DOM accessing the array of canvas
var canvas = document.getElementsByTagName("canvas")[0];
//then draw on it as needed
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
};
//load image
image.src = "http://i.imgur.com/ITWfejd.png";
</script>
</head>
<body>
<canvas width="240" height="297"></canvas>
<canvas id = "image_to_Overlay" width = "800" height = "500"></canvas>
</body>
</html>

Copying and pasting one canvas inside another canvas's corner

I have two canvases on my HTML page and what i actually want to do is pasting all stuff inside first canvas in bottom right corner of second canvas.
This is the code I was trying:
<canvas id="first"></canvas>
<canvas id="second"></canvas>
<script>
var first = document.getElementById('first').getContext('2d');
var sec = document.getElementById('second').getContext('2d');
//--code for drawing in first canvas--
var img = new Image();
img.src="imgName.jpg";
img.onload = function() {
sec.drawImage(img,0,0,sec.canvas.width,sec.canvas.height);
//Actually i want first canvas to overlap image on second canvas
var paste = new Image();
paste.src = first.canvas;
paste.onload = function() {
sec.drawImage(paste,100,100,400,600);
};
};
</script>
Problem is: second canvas shows image but doesn't shows first canvas in its bottom right corner.
Please worthy guys, i need the answer. Its very Important. Thanks in advnce to all helpers..
The way you are drawing the first canvas on the second one is not correct. You can directly draw a canvas on another canvas using drawImage() method.
var first = document.getElementById('first').getContext('2d');
var sec = document.getElementById('second').getContext('2d');
// draw on first canvas
first.fillStyle = '#07C';
first.fillRect(0, 0, first.canvas.width, first.canvas.height);
// draw image on second canvas
var img = new Image();
img.src = "http://lorempixel.com/300/300";
img.onload = function() {
sec.drawImage(img, 0, 0, sec.canvas.width, sec.canvas.height);
sec.drawImage(first.canvas, 100, 100, 100, 100); // draw first canvas on a portion of second canvas
};
body {display: flex}
<canvas id="first" width="200" height="200"></canvas>
<canvas id="second" width="200" height="200"></canvas>

In the HTML5 canvas, is there a way to rotate images in different angles?

Currently there are are two images I would like to rotate on the canvas, I tried save and restore but didn't work
function SetCanvas()
{
var canvas = document.getElementById('pic1');
if(canvas.getContext)
{
var ctx = canvas.getContext('2d');
// ctx.save();
ctx.rotate(0.5);
var image = new Image();
image.src ='ME.JPG';
image.onload = function(){
ctx.drawImage(image, 90,0,200,100);
};
}
//ctx.restore();
var canvas2 = document.getElementById("pic2");
var image2 = new Image();
image2.src = 'ME2.JPG';
if(canvas2.getContext)
{
image2.onload = function(){
ctx2=canvas2.getContext('2d');
ctx2.drawImage(image2, 0,0,200,100);
};
}
}
<ul id="picsCanvas" style="overflow:hidden;white-space:nowrap; list-style-type:none;">
<li style=" display:inline; float:left" id="first">
<canvas ID="pic1" width="300" height="360" ></canvas>
</li>
<li id="second" style="margin-top:0px; display:inline; float:left; position:absolute ">
<canvas id="pic2" width="300" height="360" style="position:absolute" ></canvas>
</li>
</ul>
Please note that the code might not be correct as it is something I did a while ago, I just want to get an idea of how to do it and if it is possible... thanks for your help.
The images are loading asynchronously. This means that that entire function (minus the onload handlers for the images happens first. Then when the images are loaded, their handlers are called. This happens in a second pass. By the time this happens, you already rotated and restored the canvas, effectively wiping the rotation out.
The simple fix is to rotate and restore the canvas inside each of the image onload handlers.
These two links give a pretty good explanation and example of how to rotate with HTML5 canvas
https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas
https://developer.mozilla.org/en/Canvas_tutorial/Basic_animations
You set the different angles when you rotate (see code example below).
The general gist of it is:
1) save the context
2) transform to, usually, the center of the image
3) rotate
4) transform back
5) draw image
6) restore
In your case, with two images, you need to transform the origin to the second image before you make the second rotation call. Below is a simplified example rotating one image. Get that sorted and then make the second transform/rotate.
Example:
var canvas = document.getElementById("yourCanvas");
var ctx = canvas.getContext("2d");
var angle = 0;
window.setInterval(function(){
angle = angle+1;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.fillStyle = "#FF0000";
// first image
ctx.translate(150,200);
ctx.rotate( angle*Math.PI/180 ); // rotate 90 degrees
ctx.translate(-150,-200);
ctx.fillStyle = "black";
ctx.fillRect(100, 150, 100, 100);
ctx.fill();
ctx.restore();
}, 5);​

Removing an image from a canvas in HTML5

there's an example, which loads 2 images:
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var img1 = new Image();
img.src = "/path/to/image/img1.png";
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
var img2 = new Image();
img2.src = "/path/to/image/img2.png";
img2.onload = function() {
ctx.drawImage(img2, 100, 100);
};
I need to remove(replace) img2 from canvas. What is the best way to do it?
I think maybe you misunderstand what a Canvas is.
A canvas is essentially a 2 dimensional grid of pixels along an 'X' axis and a 'Y' axis. You use the API to draw pixels onto that canvas, so when you draw an image you're basically drawing the pixels that make up that image onto your canvas. The reason there is NO method that lets you just remove an image, is because the Canvas doesn't know there's an image there in the first place, it just see pixels.
This is unlike the HTML DOM (Document Object Model) where everything is a HTML element, or an actual 'thing' you can interact with, hook-up script events to etc. this isn't the case with stuff you draw onto a Canvas. When draw a 'thing' onto a Canvas, that thing doesn't become something you can target or hook into, it's just pixels. To get a 'thing' you need to represent your 'thing' in some way such as a JavaScript object, and maintain a collection of these JS objects somewhere. This how how Canvas games work. This lack of a DOM-like structure for Canvas makes rendering very fast, but can be a pain for implementing UI elements that you can easily hook into and interact with, remove etc. For that you might want to try SVG.
To answer your question, simply paint a rectangle onto your Canvas that covers up your image by using the same X/Y coords and dimensions you used for your original image, or try Pointy's solution. 'Cover-up' is probably the wrong terminology, since you're actually replacing the pixels (there are no layers in Canvas).
It's not clear what you want the canvas to show when the image is gone. If you want it to be transparent, you could get the image data and fill it with transparent pixels:
var img = ctx.createImageData(w, h);
for (var i = img.data.length; --i >= 0; )
img.data[i] = 0;
ctx.putImageData(img, 100, 100);
where "w" and "h" would be the width and height of your original image.
edit — if you just want another image there, why not just put one there? It will overwrite whatever pixels are there on the canvas.
You can use clearRect() function to clear the image area.Rather then clearing whole context you can clear only the image area using this:
ctx.clearRect(xcoordinate_of_img1,ycoordinate_of_img1,xcoordinate_of_img1 + img1.width ,ycoord_of_img1 +img1.height );
If what "Sunday Ironfoot" said is right, then the best way to remove an image is by drawing the images once again from scratch. For this, you need to have an array of images and draw only the ones you use. For example,
function EmptyClass{};
var img=new Array();
img[0]=new EmptyClass;
img[0].i=new Image();
img[0].src="yourfile1.jpg";
img[0].enabled=true;
img[1]=new EmptyClass;
img[1].i=new Image();
img[1].src="yourfile2.jpg";
img[1].enabled=false;// <-------- not enabled, should not be drawn equivalent to removing
img[2]=new EmptyClass;
img[2].i=new Image();
img[2].src="yourfile3.jpg";
img[2].enabled=true;
for(var i=0;i<3;i++){
if(img[i].enabled)ctx.drawImage(img[i], 100, 100);
}
P.S. I am creating an engine for javascript canvas. Will post it within a week
Peace
You can erase an image by drawing the same image again, using a different globalCompositeOperation
ctx.globalCompositeOperation ="xor"
ctx.drawImage(img2, 100, 100);
See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
Unlike drawing things yourself, if you 'replace' THE image on a canvas, the old one is still there.
Canvas c2;
...
if (null != Image2) {
var ctx = c2.getContext("2d");
ctx.clearRect(0, 0, c2.width, c2.height);
}
Can you overlay canvas objects (I guess I should try before asking, you can -1 one me for being lazy). I guess I'd be interested in have one canvas element as a background, and then another for a layer objects that pop in and out of view. Might be a little more efficient then having to redraw every image if one gets deleted or moved. I'll play around and see what I can find.
There is ``ctx.clearRect(x, y, w, h)'' but this is not a good way to remove the shape, because it will remove any full or partial shapes in the same area of the removed shape. This shouldn't happen, and may remove one or more shapes, I've found it's best to save all your shapes in a list that usually comes from the database using backend language or ajax request, and add for it's shape object an identifier, when you need to remove a shape just remove that shape from the list using the id or the index, then Redraw the canvas with this new array of shapes without a deleted shape, the next time the page loads, this shape will not be added to this list, because it should be deleted from database.
const projectStamps = [{image_id: 'scream', x: 100, y: 100, id: 1}, {image_id: 'scream', x: 100, y: 100, id: 2}, {image_id: 'scream', x: 50, y: 0, id: 3}, {image_id: 'scream', x: 150, y: 0, id: 4}];
let currentShapes = [];
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
function validStampObj(stamp){
if (typeof(stamp.x) !== 'number' || typeof(stamp.y) !== 'number' || typeof(stamp.image_id) === 'undefined' || !document.getElementById(stamp.image_id)){
return false;
} else {
return true;
}
}
function addStamp(stamp){
if (!validStampObj(stamp)){
console.log("can not add stamp, invalid object");
return false;
}
const image = document.getElementById(stamp.image_id);
stamp['w'] = image.getBoundingClientRect().width;
stamp['h'] = image.getBoundingClientRect().height;
ctx.drawImage(image, stamp.x, stamp.y, stamp.w, stamp.h);
currentShapes.push(stamp);
return stamp;
}
let id = 1;
window.onload = function() {
drawProject();
};
function clearCanvas(){
currentShapes = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
return true;
}
const projectImage = document.getElementById("project_image");
function drawProject(){
if (!projectImage){console.log('missing project image element');return false;}
clearCanvas();
ctx.drawImage(projectImage,0,0);
projectStamps.forEach( (stamp)=>{
addStamp(stamp);
});
}
function removeStamp(targetId){
let targetI = false;
for (let i=0; i<projectStamps.length; i++){
if (projectStamps[i].id == targetId){
targetI = i;
break;
}
}
if (targetI !== false){
/* remove the stamp from drawing stamps list and redraw the data */
projectStamps.splice(targetI,1);
drawProject();
}
}
setTimeout( ()=>{
removeStamp(3);
console.log("removed icon with id 3");
}, 2500 );
<p>Image to use:</p>
<img id="scream" width="35" height="35"
src="https://i.ibb.co/wYyc259/iconimage.png" alt="The Scream">
<img id="project_image" width="450" height="300"
src="https://i.ibb.co/sK5HtQy/bulding-image.png" style="position:absolute;left:-15455px;">
<p>Canvas:</p>
<button onclick="drawProject()">Redraw things</button>
<canvas id="myCanvas" width="450" height="300"
style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
notes if you used clearRect in this example it will remove the part of main image of the canvas not just the icon with id 3 like this code does hope it helps.

Categories