Images on first load don't show on canvas - javascript

I want to pass a list of images and draw them each one for canvas.
My view.py:
def myview(request):
...
lista=Myobject.objects.filter(tipo=mytipo)
numero_oggetti = range(len(lista))
lista_formattata=[]
for elem in lista:
lista_formattata.append('/media/'+str(elem.myfield))
context_dict['lista']=lista_formattata
context_dict['numero_oggetti']=numero_oggetti
return render(request, 'mytemplate.html', context_dict)
My template.html:
<script>
<!--
window.onpageshow = function() {
myfunction({{lista|safe}});
};
-->
</script>
{% for c in numero_oggetti %}
<canvas id='componenti_canvas{{ c }}' width='60' height='75' style="border:1px solid #000000;">
Your browser does not support the HTML5 canvas tag.
</canvas>
{% endfor %}
My script.js:
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image();
base.src = lista[i];
ctx.scale(0.5,0.5);
ctx.drawImage(base, 0, 0);
};
};
This code works but sometimes the images show, sometimes don't (all of them or no one). When I load the page they don't show, when I re-load the page they show up. If I wait some minutes and re-load they don't show again.
I'm using firefox and in the console log when say GET image_name.png HTTP/1.0 200 they don't show (sometimes they are in cache, sometimes not... it don't make difference), when it don't say nothing they show.
I tried:
-setTimeout
-call the list with an ajax request with cache: false, async: false
-base.onload, like that:
base.onload = function(){
ctx.scale(0.5,0.5);
ctx.drawImage(base, 0, 0);
}
but or the images don't show never or they show in this way. I can give details, of course I can have done errors.
Edit: in the comment say to use onload.
My script.js:
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image();
base.onload = function() {
ctx.drawImage(base, 0, 0);
};
base.src = lista[i];
ctx.scale(0.5,0.5);
};
};
It draws only the last image on the last canvas (I have many canvas and I draw an image for each).

This will not work because you keep overwriting the image for every iteration of the loop. There is only one variable called base, it can only hold one image so all the ones before it are lost.
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image(); // second and more loops you over write base
base.onload = function() {
ctx.drawImage(base, 0, 0); // when it load only the last image is in base
// there is only one var called base so it
// can not hold more than one image
};
base.src = lista[i];
ctx.scale(0.5,0.5);
};
};
Use a function to wrap all the required vars so that you create a unique set for each image.
function myfunction(lista) {
lista.forEach((name,i)=>{ // each time the call back is called a
// new set of variables are created to
// store each unique image.
var base = new Image();
base.src = name;
base.onload = function() { ctx.drawImage(base, 0, 0); };
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
ctx.scale(0.5,0.5);
});
}

Related

HTML Canvas - passing a background image to Canvas while it's also passing base64 data

I'm currently trying to do some Javascript work in Laserfiche forms which requires me to save the base64 data for an image in a separate text area, and feed that data back into the image to allow the canvas to be turned into an image in which I can save into the system.
The issue is I'm trying to have a background image in which the user can draw on (in this case, a vehicle that they can draw a circle on to indicate where the damage is). I am using sketch.js to allow the drawing part of the task.
From what I've read is that the background CSS cannot be saved into the canvas. That's fine but how do I pass the background image when I'm already grabbing the base64 data and passing that back into my canvas?
The saveimage class belongs to the text area and the imagefinish belong to the checkbox that they mark when the image is ready
html
<div class="demo" id="colors_demo">
<div class="tools">
Marker
Eraser
Download
</div>
<canvas id="colors_sketch" width="750" height="500" style="border:2px solid #000000 ; background: url(http://localhost/forms/img/vanImage.jpg"></canvas>
</div>
<input name="Field11" id="Field11-0" type="checkbox" value="isLocked" vo="e" data-parsley-class-handler="#Field11" data-parsley-errors-container="#Field11" data-parsley-multiple="Field11">
<textarea id="Field13" name="Field13" aria-labelledby="Field13" class="cf-medium" rows="3" vo="e" data-parsley-id="28"></textarea>
Javascript
//submitted form
if ($('[name=IsLocked]').val() == 'True') {
var myCanvas = document.getElementById('colors_sketch');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function() {
ctx.drawImage(this, 0, 0, myCanvas.width, myCanvas.height);
}
img.src = $('.saveimage .cf-field').text();
}
else {
//fill form
//$.getScript('http://localhost/Forms/js/sketch.js', function() {
$.getScript('https://rawgit.com/intridea/sketch.js/gh-pages/lib/sketch.js', function() {
//script is loaded and executed put your dependent JS here
$.each(['#f00', '#ff0', '#0f0', '#0ff', '#00f', '#f0f', '#000', '#fff'], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-color='" + this + "' style='width: 10px; background: " + this + ";'></a> ");
});
$.each([3, 5, 10, 15], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-size='" + this + "' style='background: #ccc'>" + this + "</a> ");
});
//$('#colors_sketch').sketch();
$('#colors_sketch').sketch({defaultColor: "#000"});
});
$('.imagefinish input').change(function(){
if(this.checked) {
var myCanvas = document.getElementById('colors_sketch');
$('.saveimage textarea').val(myCanvas.toDataURL());
}
});
}
I was able to add an image by adding a variable for my image path
var image = 'http://localhost/forms/img/vanImage.jpg'
and I also added the two lines to my onload for the style of "myCanvas". I have a feeling that this solution will only work because of how Laserfiches forms software works but the marked answer is also correct.
img.onload = function() {
ctx.drawImage(this, 0, 0, myCanvas.width, myCanvas.height);
myCanvas.style.backgroundRepeat = "no-repeat";
myCanvas.style.backgroundImage = 'url('+image+')'
}
img.src = $('.saveimage .cf-field').text();
}
Load the background image on page load, or an appropriate time and when the client is ready, draw the background onto the canvas behind the user content using ctx.globalCompositeOperation = "destination-over";
Create an image to hold the background.
const backgroundImage = new Image();
backgroundImage.src = "http://localhost/forms/img/vanImage.jpg";
You need to ensure that the image has loaded when the client clicks ready, incase it has not loaded you can set a callback that will call back the ready function if needed.
var backgroundLoadedCallback = null;
backgroundImage.onload = function(){
if( typeof backgroundLoadedCallback === "function"){
backgroundLoadedCallback();
}
}
Then create the canvas -> textarea function
function canvasToTextarea(){
const myCanvas = document.getElementById('colors_sketch');
const ctx = myCanvas.getContext("2d");
ctx.globalCompositeOperation = "destination-over"; // make sure the background go under the drawn pixels
// draw and fit background to the canvas
ctx.drawImage(backgroundImage,0,0,ctx.canvas.width,ctx.canvas.height);
// then convert to URL for textarea
$('.saveimage textarea').val(myCanvas.toDataURL());
}
In the checked function
$('.imagefinish input').change(function(){
if(this.checked) {
if(backgroundImage.complete) { // image has loaded so all good
canvasToTextarea(); // put canvas data URL to textarea
} else { // background has not yet loaded (or could be an error you will have to deal with that as well
// set the callback to the canvasToTextarea function
backgroundLoadedCallback = canvasToTextarea;
// when the background has loaded the canvas and background
// will be moved to the textarea as a data URL
}
}
});
Or modify sketch.js
Below is the draw function from sketch.js (and it`s very old school)
Sketch.prototype.redraw = function() {
var sketch;
this.el.width = this.canvas.width();
this.context = this.el.getContext('2d');
sketch = this;
$.each(this.actions, function() {
if (this.tool) {
return $.sketch.tools[this.tool].draw.call(sketch, this);
}
});
if (this.painting && this.action) {
return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
}
};
Just replace it with the following. You dont need to modify the sketch.js file justy overwrite the redraw Prototype
In your code load the background and set the new redraw
const backgroundImage = new Image();
backgroundImage.src = "http://localhost/forms/img/vanImage.jpg";
// replace Sketch.js redraw function
Sketch.prototype.redraw = function(){
var sketch;
// dont need the next line use clear instead
// this.el.width = this.canvas.width();
const ctx = this.context = this.el.getContext('2d');
// clear canvas
this.context.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// If backgroundimage complete draw it first
if(backgroundImage && backgroundImage.complete){
ctx.drawImage(backgroundImage,0,0,ctx.canvas.width,ctx.canvas.height);
}
// back to the original code. :P
sketch = this;
$.each(this.actions, function() {
if (this.tool) {
return $.sketch.tools[this.tool].draw.call(sketch, this);
}
});
if (this.painting && this.action) {
return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
}
}

javascript canvas - check if images created with toDataURL() are loaded

I'm loading an image into my albImg array.
in my loop i then do this:
for(var j = 1; j < albImg.length; j++){
if(albImg[j].complete == true && albImg[j].width > 0){
loadedimages++;
}
}
to make sure all my images are loaded.
I then call my flipImg() function like this:
if(loadedimages == albImg.length-1){
flipImg();
}
I then flip an image and
ctx2.save();
ctx2.scale(-1, 1);
for (var i = RszSpriteCount; i < sprites.length; i++) {
ctx2.drawImage(albImg[sprites[i][0]], sprites[i][1], sprites[i][2], sprites[i][3], sprites[i][4], 0 - (sprites[i][1] + sprites[i][3]), sprites[i][2], sprites[i][3], sprites[i][4]);
}
ctx2.restore();
var flipSz = albImg.length;
albImg[flipSz] = new Image();
albImg[flipSz].src = cnv2.toDataURL();
Here's where my problem begins.
The new image I created - albImg[5] - can't be displayed until it is loaded.
But it is created as if it already is loaded.
That is to say that:
albImg[5].width is already set (to 750) before I can display it.
albImg[5].complete is set to true, before I can display it.
albImg[5].onload = ctx.drawImage(albImg[5], 0, 0); will try to draw the image before it is loaded.
How can I check if my flipped image really is loaded before I display it? in Javascript?
(due to circumstances I'm not using jQuery for this)
Please help.
Your main error is in how you do set the onload event handler :
albImg[5].onload = ctx.drawImage(albImg[5], 0, 0)
will set the return value of drawImage() (undefined) to the onload listener.
What you want is
albImg[5].onload = e => ctx.drawImage(albImg[5], 0, 0);
or
albImg[5].onload = function(){ ctx.drawImage(this, 0, 0) };
For the complete and width properties set to true, it's because while the loading of an Image is always async, in your case, the image is probably already HTTP cached.
Since the HTTP loading and the javascript execution are not executed on the same thread, it is possible that the Image actually loaded before the browser returns its properties.
But even then, the onload event will fire (best to set it before the src though).
var cacher = new Image();
cacher.onload = function(){
var img = new Image();
img.onload = function(){
console.log('"onload" fires asynchronously even when cached');
};
img.src = c.toDataURL();
console.log('cached : ', img.complete, img.naturalWidth);
}
cacher.src = c.toDataURL();
console.log('before cache :', cacher.complete, cacher.naturalWidth);
<canvas id="c"></canvas>
So when dealing with an new Image (not one in the html markup), always simply listen to its onload event.
Now, with the few information you gave in your question, it would seem that you don't even need these images, nor to deal with any of their loadings (except for the sprites of course), since you can directly and synchronously call ctx.drawImage(CanvasElement, x, y).
const ctx = c.getContext('2d');
ctx.moveTo(0, 0);
ctx.lineTo(300, 75);
ctx.lineTo(0, 150);
ctx.fillStyle = 'rgba(120,120,30, .35)';
ctx.fill();
const flipped = c.cloneNode(); // create an offscreen canvas
const f_ctx = flipped.getContext('2d');
f_ctx.setTransform(-1, 0,0,1, c.width, 0);// flip it
f_ctx.drawImage(c,0,0);// draw the original image
// now draw this flipped version on the original one just like an Image.
ctx.drawImage(flipped, 0,0);
// again in 3s
setTimeout(()=>ctx.drawImage(flipped, 150,0), 3000);
<canvas id="c"></canvas>

Firefox drawing blank Canvas when restoring from saved base64

I am working with a single canvas that allows the user to click on a window pane in a window image. The idea is to show where the user has clicked. The image will then be modified (by drawing a grill on the window) and then saved to in JPEG. I am saving the canvas image prior to the click function because I don't want the selection box to show in the final image. However, Firefox often displays a blank canvas when restoring the canvas where IE and Chrome do not. This works perfectly in Chrome and IE. Any suggestions? Does Firefox have a problem with toDataURL()? Maybe some async issue going on here? I am also aware that saving a canvas in this fashion is memory intensive and there may be a better way to do this but I'm working with what I have.
Code:
/**
* Restores canvas from drawingView.canvasRestorePoint if there are any restores saved
*/
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.src = drawingView.canvasRestorePoint.pop();
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
}
},
/**
* Pushes canvas into drawingView.canvasRestorePoint
*/
saveCanvas:function()
{
var canvas = document.getElementById("drawPop.canvasOne");
var urlData = canvas.toDataURL();
drawingView.canvasRestorePoint.push(urlData);
},
EXAMPLE OF USE:
readGrillInputs:function()
{
var glassNum = ir.get("drawPop.grillGlassNum").value;
var panelNum = ir.get("drawPop.grillPanelNum").value;
drawingView.restoreCanvas();
drawEngine.drawGrill(glassNum, panelNum,null);
drawingView.saveCanvas();
},
sortClick:function(event)
{
..... //Sorts where user has clicked and generates panel/glass num
.....
drawingView.showClick(panelNum, glassNum);
},
showClick:function(panelNum, glassNum)
{
var glass = item.panels[panelNum].glasses[glassNum];
var c = drawEngine.context;
drawingView.restoreCanvas();
drawingView.saveCanvas();
c.strokeStyle = "red";
c.strokeRect(glass.x, glass.y, glass.w, glass.h);
},
By just looking at the code setting the img.src is an async action to retrieve the image, so when you try to draw it 2 lines later to the canvas, it probably hasn't been loaded yet (having it in cache will make it return fast enough that it might work).
You should instead use an img.onload function to draw the image when it has loaded.
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.onload = function() {
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
};
img.src = drawingView.canvasRestorePoint.pop();
}
},

HTML5/Javascript Image loading method & passing to variable

I have some code for loading images.
var assets = {
total:0,
success:0,
error:0
};
var stillLoading = true;
var img = {};
function LoadImage(name, path){
var toLoad = new Image();
toLoad.src = path;
assets.total++;
toLoad.addEventListener("load", function(){
assets.success++;
console.log(name + " loaded.");
img[name] = toLoad;
}, false);
toLoad.addEventListener("error", function(){
assets.error++;
}, false);
};
function Loading(){
if (assets.success == assets.total){
if (stillLoading){
console.log("All assets loaded. Starting game.");
};
stillLoading = false;
return false;
}else{
stillLoading = true;
return true;
};
};
May still be inefficient, and ugly since I'm new to practicing javascript, open to suggestions. It loads the image and tells the main program when all the assets have finished loading through the function Loading(), and then adds the image to the object img.
I've been using this for a while now for my images, and it works.
For example, if I did.
LoadImage("Car", "imageOfCar.png");
ctx.drawImage(img.Car, 0, 0);
this would draw the image just fine to the canvas.
However, when I assign another variable the image, which for various reasons I want to do, such as assigning images to objects. e.g.
var secondCar = img.Car
then try to draw it.
ctx.drawImage(secondCar, 0, 0);
I get this error.
Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap)'
If it works for the initial variable, it should act the same way towards another variable that has just been assigned the exact same thing. So why is it am I getting this error?
If I was to load the image the typical way that doesn't check if it's finished loading.
img.Car = new Image();
img.Car.src = "imageOfCar.png";
secondCar = img.Car;
ctx.drawImage(secondCar);
This would work.
The behaviour here is a bit confusing, could someone explain to me what is happening, and perhaps suggest a way to fix it?
EDIT: Just to clarify.
This is the html file, called index.html.
<!DOCTYPE html>
<head>
<title>HTML5 Game Base</title>
<link rel = "stylesheet" type = "text/css" href = "styles.css">
</head>
<body>
<canvas id="screen" width="270" height="480" style="border:1px solid #000000;"></canvas>
<script src = "script.js"></script>
</body>
</html>
The canvas is set up as screen. All the javascript code I've displayed above takes place within script.js which is called in index.html.
This is how screen is called within the script.js.
var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
This is what ctx.drawImage() is referencing.
I realize this won't be the most helpful answer, but I tinkered around with your code a little. This is what I used:
<!DOCTYPE html>
<head>
<title>HTML5 Game Base</title>
</head>
<body>
<canvas id="screen" width="270" height="480" style="border:1px solid #000000;"></canvas>
<script>
var stillLoading = true;
var img = {};
var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
assets = {};
assets.total = 0;
function LoadImage(name, path){
var toLoad = new Image();
toLoad.src = path;
assets.total++;
toLoad.addEventListener("load", function(){
//assets.success++;
console.log(name + " loaded.");
img[name] = toLoad;
}, false);
toLoad.addEventListener("error", function(){
assets.error++;
}, false);
}
</script>
</body>
</html>
Then in Chrome's console I typed
LoadImage("Car", "map.png");
LoadImage("un", "Untitled.png");
ctx.drawImage(img.Car, 0, 0);
ctx.drawImage(img.un, 0, 0);
and get the expected result of images loading in the canvas. Even when assigning one of the img images to a new variable, this works as expected.
var second = img.Car
ctx.drawImage(second, 0, 0)
It appears everything is working fine when run manually, so my guess would be timing. When are you running these commands? Are they in the js file or from the console?
It would appear your LoadImage function is fine. Sorry this is not super helpful, but hopefully will help you rule out where not to look for the problem.
One approach could be to utilize Promise , as load event of new Image is asynchronous secondCar could be undefined when used as parameter within setInterval, e.g., load event of img may not be complete when var secondCar = img.Car applied after call to LoadImage; also added variable reference for setInterval for ability to call clearInterval() if needed
var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
var interval = null;
var assets = {
total: 0,
success: 0,
error: 0
};
var stillLoading = true;
var img = {};
function LoadImage(name, path) {
return new Promise(function(resolve, reject) {
var toLoad = new Image();
assets.total++;
toLoad.addEventListener("load", function() {
assets.success++;
console.log(name + " loaded.");
img[name] = toLoad;
// resolve `img` , `assets` object
resolve([img, assets])
}, false);
toLoad.addEventListener("error", function() {
assets.error++;
reject(assets)
}, false);
toLoad.src = path;
})
};
function Loading() {
if (assets.success == assets.total) {
if (stillLoading) {
console.log("All assets loaded. Starting game.");
};
stillLoading = false;
return false;
} else {
stillLoading = true;
return true;
};
};
var promise = LoadImage("Car", "http://pngimg.com/upload/audi_PNG1736.png");
promise.then(function(data) {
// `data` : array containing `img` , `assets` objects
console.log(data);
var secondCar = data[0].Car;
interval = setInterval(function() {
if (!(Loading())) {
ctx.drawImage(secondCar, 0, 0);
};
}, 1000 / 60);
});
<canvas id="screen" width="1000" height="700" style="border:1px solid #000000;"></canvas>
Solved. Turns out it was a timing issue. In the example I gave, when secondCar is assigned img.Car, img.Car had not yet loaded.
Instead I created a new function called Initialise(), and called it from within Loading(). So from now on I would just have to initialise all my variables that may require images from within Initialise(). This way, variables can only be assigned images after they've loaded.
New Code:
var canvas = document.getElementById("screen");
var ctx = canvas.getContext("2d");
var assets = {
total:0,
success:0,
error:0
};
var stillLoading = true;
var img = {};
function LoadImage(name, path){
var toLoad = new Image();
toLoad.src = path;
assets.total++;
toLoad.addEventListener("load", function(){
assets.success++;
console.log(name + " loaded.");
img[name] = toLoad;
}, false);
toLoad.addEventListener("error", function(){
assets.error++;
}, false);
};
function Loading(){
if (assets.success == assets.total){
if (stillLoading){
console.log("All assets loaded. Starting game.");
Initialise();
};
stillLoading = false;
return false;
}else{
stillLoading = true;
return true;
};
};
LoadImage("Car", "http://pngimg.com/upload/audi_PNG1736.png");
function Initialise(){
window.secondCar = img.Car;
};
setInterval(function(){
if (!(Loading())) ctx.drawImage(secondCar, 0, 0);
}, 1000/60);
Works now, thanks for the help although I ended up solving it myself. I would still appreciate any tips on how to improve it. Or knowing that I'm new to javascript, any nitpicks to help me conform to javascript conventions.

How to get click event on images which is placed on canvas

I have create program to display multiple images on canvas. Now I want to get that images data using mouse click event which is placed on canvas.
My JavaScript cod is -
var canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
canvas.width = 720;
canvas.height = 480;
//I got images data in one array
var imageobj = new Array();
for (var d=0;d<calloutImageArray.length;d++)
{
imageobj[d] = new Image();
(function(d)
imageobj[d].src = sitePath+"ATOM/chapter1/book/"+calloutImageArray[d];
imageobj[d].onload = function()
{
ctx.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d],calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
Fairly easily done:
Listen for mousedown events using canvas.addEventListener
On mousedown, check if the mouse is inside any image.
Get the image data for the image under the mouse.
Example code:
function handleMousedown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position
var mouseX=e.clientX-BBoffsetX;
var mouseY=e.clientY-BBoffsetY;
// loop through each image and see if mouse is under
var hit=-1;
for(var i=0;i<imageobj.length;i++){
var x=calloutImageArrayX[i];
var y=calloutImageArrayY[i];
var w=calloutImageArrayW[i];
var h=calloutImageArrayH[i];
if(mouseX>=x && mouseX<=x+w && mouseY>=y && mouseY<=y+h){
hit=i;
}
}
// you clicked the image with index==hit
// so get its image data
if(hit>=0){
var imageData=ctx.getImageData(
calloutImageArrayX[hit],
calloutImageArrayY[hit],
calloutImageArrayW[hit],
calloutImageArrayH[hit]);
// now do your thing with the imageData!
}
}
Example code and a Demo:
var $results=document.getElementById('results');
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var BB,BBoffsetX,BBoffsetY;
function setBB(){
BB=canvas.getBoundingClientRect();
BBoffsetX=BB.left;
BBoffsetY=BB.top;
}
setBB();
window.onscroll=function(e){ setBB(); }
var imageobj=[];
var calloutImageArrayX=[10,125,10,125];
var calloutImageArrayY=[10,10,150,150];
var calloutImageArrayW=[];
var calloutImageArrayH=[];
// put the paths to your images in imageURLs[]
var imageURLs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/character3.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/character2.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/character1.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stack1/avatar.png");
// the loaded images will be placed in imageobj[]
var imagesOK=0;
startLoadingAllImages(imagesAreNowLoaded);
// Create a new Image() for each item in imageURLs[]
// When all images are loaded, run the callback (==imagesAreNowLoaded)
function startLoadingAllImages(callback){
// iterate through the imageURLs array and create new images for each
for (var i=0; i<imageURLs.length; i++) {
// create a new image an push it into the imageobj[] array
var img = new Image();
img.crossOrigin='anonymous';
// Important! By pushing (saving) this img into imageobj[],
// we make sure the img variable is free to
// take on the next value in the loop.
imageobj.push(img);
// when this image loads, call this img.onload
img.onload = function(){
// this img loaded, increment the image counter
imagesOK++;
// if we've loaded all images, call the callback
if (imagesOK>=imageURLs.length ) {
callback();
}
};
// notify if there's an error
img.onerror=function(){alert("image load failed");}
// set img properties
img.src = imageURLs[i];
}
}
// All the images are now loaded
// Do drawImage & fillText
function imagesAreNowLoaded(){
// the imageobj[] array now holds fully loaded images
// the imageobj[] are in the same order as imageURLs[]
// add widths & heights to the appropriate arrays
for(var i=0;i<imageobj.length;i++){
calloutImageArrayW.push(imageobj[i].width);
calloutImageArrayH.push(imageobj[i].height);
}
// listen for mousedown events
canvas.onmousedown=handleMousedown;
draw();
}
function draw(){
ctx.clearRect(0,0,cw,ch);
for(var d=0;d<imageobj.length;d++){
ctx.drawImage(imageobj[d],
calloutImageArrayX[d], calloutImageArrayY[d],
calloutImageArrayW[d], calloutImageArrayH[d]);
}
}
function handleMousedown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position
var mouseX=e.clientX-BBoffsetX;
var mouseY=e.clientY-BBoffsetY;
// loop through each image and see if mouse is under
var hit=-1;
for(var i=0;i<imageobj.length;i++){
var x=calloutImageArrayX[i];
var y=calloutImageArrayY[i];
var w=calloutImageArrayW[i];
var h=calloutImageArrayH[i];
if(mouseX>=x && mouseX<=x+w && mouseY>=y && mouseY<=y+h){
hit=i;
}
}
// you clicked the image with index==hit
// so get its image data
if(hit>=0){
var imageData=ctx.getImageData(
calloutImageArrayX[hit],
calloutImageArrayY[hit],
calloutImageArrayW[hit],
calloutImageArrayH[hit]);
var pos;
switch(hit){
case 0:pos='top-left';break;
case 1:pos='top-right';break;
case 2:pos='bottom-left';break;
case 3:pos='bottomRight';break;
}
$results.innerHTML='You clicked the '+pos+' image.<br>This imageData has this length: '+imageData.data.length;
}
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4 id="results">Click on an image</h4>
<canvas id="canvas" width=300 height=300></canvas>
Take my advice and go with something like fabricJS , it will make your life very easy. In that you can easily have multiple objects on the canvas and also perform functions (Scale,rotate,pan) on them separately.

Categories

Resources