I am trying to to write undo/Redo functionality on canvas . i am using fabric-js to draw Objects . undo ?Redo is working fine but the problem is after calling undo/redo function if i click on canvas Elements goes Invisible. i tried canvas.renderAll() still i am getting problem.
Steps for Undo::
Before Element Drawn i am saving canvas.toDataURl() in an variable Array.
2.When Undo Button is clicked i am using clear method of fabric to clear canvas and then getting variable Array to Draw on canvas using Previous `toDataUrl() .
Code ::
function undoDrawOnCanvas() {
console.log('inside undodrawn');
// If we have some restore points
if (restorePoints.length > 0) {
// Create a new Image object
var oImg = new Image();
// When the image object is fully loaded in the memory...
oImg.onload = function() {
//Saving point for Redo
c_redo=document.getElementById("design_text").toDataURL("image/png");
canvas.clear();
// Get the canvas context
var canvasContext = document.getElementById("design_text").getContext("2d");
// and draw the image (restore point) on the canvas. That would overwrite anything
// already drawn on the canvas, which will basically restore it to a previous point.
canvasContext.drawImage(oImg, 0, 0);
}
// The source of the image, is the last restoration point
oImg.src = restorePoints.pop();
}
}
Related
I am making a game with the html5 canvas and I am having some trouble getting the images on screen.
//player img
var img1 = new Image();
img1.onload = function() {
console.log("image loaded");
};
img1.src = "player.png";
The image is a .png file called "player" and is saved on my desktop. Am I doing something wrong when setting the src method? Is there a better way to do this? I appreciate any help.
Well first, the image should have a path that is relative to the html document and if you are not seeing the image, it's probably because you didn't put that relative path into your code (you are only using the file name which implies the image is in the same directory as the html file).
Also, you haven't shown any code to associate the image with the canvas. This is the approach:
// Get the DOM object reference for the canvas element:
var canvas = document.getElementById("canvas");
// Get an object reference for the canvas' contextual environment:
var ctx = canvas.getContext('2d');
// Instantiate an image to use as the background of the canvas:
var img = new Image();
// Make sure the image is loaded first otherwise nothing will draw.
img.addEventListener("load", function () {
// Draw the image on the canvas at position 0, 0 (top-left):
ctx.drawImage(img, 0, 0);
});
// Wait until after wiring up the load event handler to set the image source
// This example assumes that the image is located in a sub-folder of the current folder, called images.
// Your path must be a relative reference to the location where the image is.
img.src = "images/starfield.jpg";
I'm new to this - I just can't figure out why this isn't working. When I remove Display:none from HTML, the image works correctly so I know the path to the image is correct. But it's not drawing on the canvas. Thanks for your time.
HTML:
<canvas width="840" height="900" id="Canvas6">
Your browser does not support this feature.
</canvas>
<img src="image/logo.png" id="img1" width="825" height="272" style="display:none;">
<script type="text/javascript" src="js/main.js"></script>
Main.JS JAVASCRIPT:
var theCanvas = document.getElementById('Canvas6');
if (theCanvas && theCanvas.getContext) {
var ctx = theCanvas.getContext("2d");
if (ctx) {
//Create a variable to hold our image
var srcImg = document.getElementById("img1");
//Draw an image directly onto the canvas
ctx.drawImage(srcImg, 0,0);
//Draw a scaled down image
//drawImage(srcImg, dx, dy, dw, dh)
}
}
In html file, the first best thing you have done is used the 'script' tag right at the end of the html file.
This ensures that the "Critical Render Time" is minimized, and the display items in HTML are shown first. (Not a huge impact on this case, because here you are using the JS to draw/display, but this approach is really good when you use your js for other purposes like calculations etc., and you don't want to stop the other HTML items from displaying because of an ongoing calculation.)
Now that the canvas is ready, its time to throw the image on the canvas.
Try using the border property (style="border: 2px dotted black") to see the container area of the canvas.
Hmmm !! But the image doesn't show in canvas. WHY ??
Images(or any other files) take atleast some time to get processed. By the time they are getting processed to be loaded on the screen, your canvas is already getting displayed. Hence you see an empty canvas.
So, the solution is to make everything else wait, till the time image gets loaded.
How do we do that ? Just use the "Event Listener".
EventListener is the property of Window object. (window.addEventListener("load", some_func_to_run , false);). We generally use this, when we want our window/page/browser to wait for something, but hey , we can use it for our images as well.
var cvs = document.getElementById("canvas"); // Getting the control of the canvas
var ctx = cvs.getContext("2d"); //Getting the control of the useful HTML object getContext . This object brings in a lot of useful methods like drawImage, fillRect etc.
//create images
var bg = new Image(); // Creating image objects
bg.src = "images/bg.png"; //Setting the source file
//create images ends
//load images first
bg.addEventListener("load" , draw , false); //**IMPORTANT : Just remove this line and you will start facing this problem of empty canvas again
//loading images ends
function draw() {
ctx.drawImage(bg,0,0); // Putting the image and its coordinates on the canvas
}
draw(); // Calling the draw function to put the image on canvas
<html>
<body>
<canvas id="canvas" width="288" height="512" style="border: 2px dotted black"> </canvas>
<script src="flappyBird.js"></script>
</body>
</html>
So, it all about using Event Listener and asking everything to wait till the image gets loaded.
Hope this help. :)
If you try to place an image on a Canvas before it has loaded, it will not show. It is not like the img tag that will show the image whenever it loads. I surrounded your JS with an onload and it worked for me.
document.getElementById("img1").onload = function() { /* Your JS */ };
You have to wait for the image to load before you can draw it on the canvas, so set your drawing code to run on the window load event (by which time all images are loaded). Also, you don't need to include the markup for the image on the page, where you have to then prevent it from displaying with CSS. You can just create the image object and set the source attribute in the javascript. For example:
var img = document.createElement('img');
img.src = 'image/logo.png';
window.addEventListener('load', function(){
var theCanvas = document.getElementById('Canvas6');
if (theCanvas && theCanvas.getContext) {
var ctx = theCanvas.getContext("2d");
if (ctx) {
ctx.drawImage(img, 0,0);
}
}
});
11I'm using sketch.js from here: http://intridea.github.io/sketch.js/ and jquery 2.0.0
On my page, I have a list of images presented like so:
<img src="http://url.to/image"><br><span class="background">click for background</span>
and a canvas, set up like so:
<canvas id="simple_sketch" style="border: 2px solid black;"></canvas>
relevant JavaScript:
var winwidth = 800;
var winheight = 600;
$('#simple_sketch').attr('width', winwidth).attr('height', winheight);
$('#simple_sketch').sketch();
$('.background').on('click', function(event) {
event.preventDefault();
var imgurl = $(this).parent().attr('href');
console.log('imgurl: ' + imgurl);
var n = imgurl.split('/');
var size = n.length;
var file = '../webkort/' + n[size - 1];
var sigCanvas = document.getElementById('simple_sketch');
var context = sigCanvas.getContext('2d');
var imageObj = new Image();
imageObj.src = imgurl;
imageObj.onload = function() {
context.drawImage(this, 0, 0,sigCanvas.width,sigCanvas.height);
};
alert('background changed');
});
Backgrounds are changed just as I want them to, but whenever I click on the canvas, the backgound image is cleared. As per a suggestion on this thread: html5 canvas background image disappear on mousemove I commented out this.el.width = this.canvas.width(); on line 116 of sketch.js, but to no avail.
Any help appreciated!
EDIT: jsfiddle: http://jsfiddle.net/RXFX4/1/
EDIT: Couldn't figure out how to do this with sketch.js, so instead went with jqScribble (link posted in comments) which has the ability to do this as a built-in function instead.
Find this line on the library - sketch.js and delete/comment it out.
this.el.width = this.canvas.width();
Good luck
Assign the url on the image source after the onload event. If the image is already loaded, the event is probably firing before you are hooking it. Which means that your drawImage is never being called.
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(this, 0, 0,sigCanvas.width,sigCanvas.height);
};
imageObj.src = imgurl;
EDIT: I'm going to take a shot in the dark here, since I'm not familiar with sketchjs
I'm thinking that your problem is that you are completely re-render the canvas when you click your 'change background' link. Notice that if you draw, then click the change background, you lose your drawing.
However, notice that once you click again, the background disappears, and you get your original drawing back again. This tells me that sketchjs is keeping track of what has been drawn on it's own in-memory canvas, and then it drops it onto the target. The problem, then, is that when this in-memory canvas is drawn, it completely replaces the contents of the target canvas with it's own.
I notice in some of the sketchjs examples, if you want a background they actually assign the canvas a background style. In your example, you are drawing the background directly onto the canvas. The prior probably works because sketchjs knows to incorporate the background style when it draws. However, it does not know that when you drew your fresh background image, it should be using that.
Can you just change the background style on the canvas element, instead of drawing directly on the canvas?
here is my page
http://www.dev.1over0.com/canvas/canvas_web.html
I’m having issues with the undo functionality – I think I’m getting close but here’s the issue
First I’ll tell you the basics of the drawing application – I’m layering four different canvases
http://www.dev.1over0.com/canvas/js/canvas_web.js
if you look at the js file you’ll see at the top all my comments on what I’m doing with the canvases
when a user uses a tool to draw – it actually draws it first temporarily on the imageTemp canvas –
each tool has it’s own object (pencil, rectangle, line)
with functions within for mousedown, mousemove and mouseup events
at the end of the mouseup event it calls this function
function img_update() {
contexto.drawImage(canvas, 0, 0);
saveActions();
context.clearRect(0, 0, canvas.width, canvas.height);
}
Here the image that’s on the temp canvas ends up being drawn on the imageView canvas so essentially the imageTemp canvas is being erased each time
So for the undo functionality I first declare a an empty array
var undoHistory = [];
I also declare a new image
var undoImg = new Image();
when img_update is invoked – it calls another function saveActions
function saveActions() {
var imgData = canvaso.toDataURL("image/png");
undoHistory.push(imgData);
$('#undo_canvas button').removeAttr('disabled');
}
In this function – I’m essentially saving the newly drawed image canvas into the undoHistory array
This seems to be working fine (I believe)
So after each time the permanent imageView canvas is updated is saves that state into an array
Now if you notice once you draw an image and it’s save to the imageView canvas the undo button becomes enabled
So if you click the undo button it calls this function
function undoDraw() {
if(undoHistory.length > 0){
$(undoImg).load(function(){
contexto.drawImage(undoImg, 0,0);
});
undoImg.src = undoHistory.pop();
if(undoHistory.length == 0) {
$('#undo_canvas button').attr('disabled','disabled');
}
}
}
Here what I’m trying to do is take the previous image state and draw it on the canvas
It’s working in a way that it affects the z-index of the images but not getting rid of the images
And you have to click it twice as well which confuses me
So if you can try drawing out three rectangles on top of each other
You can click the undo button and it will effect the z-index – click it three times you’ll see what I mean so it's sort of working, maybe ;-{
You have to clear the canvas before you draw the last image, otherwise it will draw an image onto the previous canvas;
Also, you pop the last image which is the one you just've pushed in (this is why you have to click twice). So try something like this ( you might have to adapt the code I'm not sure it works out of the box)
function undoDraw(){
if(undoHistory.length > 0){
$(undoImg).load(function(){
contexto.clearRect(0,0, canvas.width, canvas.height);
contexto.drawImage(undoImg, 0,0);
});
undoHistory.pop();
undoImg.src = undoHistory.pop();
if(undoHistory.length == 0) {
$('#undo_canvas button').attr('disabled','disabled');
}
}
}
I'm following a tutorial on importing and displaying images on an HTML5 canvas. Everything works fine, until I try to change the image itself. For example, I'll have a yellow circle as my image, and the script works fine. But if I open the image itself in Paint and change the circle to red, and refresh the page, the circle won't show up until I click or refresh again a second time manually. Here is the code snippet I'm using:
var topMap = new Image();
topMap.src = "topMap.png";
function drawMap() {
context.clearRect(0, 0, WIDTH, HEIGHT);
context.drawImage(topMap, 0, 0);
}
function init() {
drawMap();
}
init();
The circle is probably not showing up because you are drawing it before the image is loaded. Change your last statement to:
// Lets not init until the image is actually done loading
topMap.onload = function() {
init();
}
The reason it works after you hit refresh is because the image is now pre-loaded into the cache.
You always want to wait for any images to load before you attempt to draw them or nothing will show up on the canvas instead.