I'm really struggling with the changing of my canvas drawn image so I thought I would see if anyone could assist me on here or offer advice.
I've drawn a static flag in canvas, and I've also drawn a waving flag. I'm trying to get this flag to wave on mouseover.
I initially thought that I was going to have to create two separate files, one for the static and one for the waving aspect. Then save each of them as a jpg/gif image using window.location = canvas.toDataURL("image/");.
But I've just discovered that you can apparently do this all in the same file via jquery/hover. Which seems a lot simpler and a more efficient way of doing it.
Here is the code for the waving flag:
window.onload = function(){
var flag = document.getElementById('banglaFlag');
banglaStatic( flag, 320 );
var timer = banglaWave( flag, 30, 15, 200, 200 );
};
function banglaStatic( canvas, width ){
//Drawing the Bangladesh flag.
//Declaring variables that regard width and height of the canvas.
//Variables C to L are needed for the waving function.
var a = width / 1.9;
var b = 200;
var c = 7*a/13;
var l = a / 13;
canvas.width = b;
canvas.height = a;
var ctx = canvas.getContext('2d');
var radius = 45;
};
function banglaWave( canvas, wavelength, amplitude, period, shading ){
var fps = 30;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var od = ctx.getImageData(0,0,w,h).data;
// var ct = 0, st=new Date;
return setInterval(function(){
var id = ctx.getImageData(0,0,w,h);
var d = id.data;
var now = (new Date)/period;
for (var y=0;y<h;++y){
var lastO=0,shade=0;
for (var x=0;x<w;++x){
var px = (y*w + x)*4;
var o = Math.sin(x/wavelength-now)*amplitude*x/w;
var opx = ((y+o<<0)*w + x)*4;
shade = (o-lastO)*shading;
d[px ] = od[opx ]+shade;
d[px+1] = od[opx+1]+shade;
d[px+2] = od[opx+2]+shade;
d[px+3] = od[opx+3];
lastO = o;
}
}
ctx.putImageData(id,0,0);
// if ((++ct)%100 == 0) console.log( 1000 * ct / (new Date - st));
},1000/fps);
}
Thanks in advance for any advice/assistance.
I am not sure where your problem is. I did not see any event handling code, so I assume that's your question:
Define a function to "handle the mouse event". For example, if you want to move the flag when the user moves the mouse over it, define something like:
function mouseMove(event) {
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
}
Then, register this function to be called when the mouse moves:
canvas.addEventListener("mousemove", mouseMove, false);
canvas is the canvas you paint the flag on, "mousemove" is the name of the event (many more exist, such as "mousedown", "mouseup", "mouseout" (leaving canvas), "mousewheel", etc.), mouseMove is the name of your function (the event handler, as it's called).
Events are a little different from browser to browser (and even browser version), so you might need to implement different event handler if you need it across browsers.
Hoping this helped...
canvas is like a sheet. there is no any object on which you can hover.
for doing what you wanted to do is just,bound an area on the flag,
follow the 'virtualnobi' answer and calculate if mouse co-ordinate falls on that region,
if true do what ever you want.
like
if (mouseX<100 && mouseX>0 && mouseY>0 && mouseY<100){
//animate the flag
}
use mouseX=event.clientX;
mouseY=event.clientY;
bounded area is x=(0,100) , y=(0,100) here.
Related
I am making a battleship game with polar coordinates. After the user chooses two points, a battleship should be drawn in the middle. My Battleship constructor looks like this:
function Battleship(size, location, source){
this.size = size;
//initializing the image
this.image = new Image();
this.image.src = source;
this.getMiddlePoint = function(){
//get midpoint of ship
...
}
this.distanceBetween = function(t1, t2){
//dist between two points
}
this.display = function(){
var point = [this.radius];
point.push(this.getMiddlePoint());
point = polarToReal(point[0], point[1] * Math.PI / 12);
//now point has canvas coordinates of midpoint
var width = this.distanceBetween(this.info[0][0], this.info[this.info.length-1][0]);
var ratio = this.image.width / width;
ctx.drawImage(this.image, point[0] - width/2, point[1] - this.image.height / ratio / 2, width, this.image.height / ratio);
//draws the image
}
}
The display method of each ship gets called at a certain point (after the user has chosen the location). For some reason, the images do not show the first time I do this, but when I run this code at the very end:
for(var i = 0; i<playerMap.ships.length; i++){
playerMap.ships[i].display();
}
All ships are displayed correctly (not aligned well, but they are displayed). I think there is a problem with loading the images. I am not sure how to fix this. I tried using image.onload but I never got that to work. I also tried something like this:
var loadImage = function (url, ctx) {
var img = new Image();
img.src = url
img.onload = function () {
ctx.drawImage(img, 0, 0);
}
}
but the same problem kept happening. Please help me fix this problem. Here is the game in its current condition. If you place ships, nothing happens, but after you place 5 (or 10) ships, they suddenly all load.
EDIT:
I solved the problem by globally defining the images. This is still very bad practice, since I wanted this to be in the battleship object. This is my (temporary) solution:
var sub = [];
for(var i = 1; i<5; i++){
sub[i] = new Image();
sub[i].src = "/img/ships/battleship_"+i+".png";
}
I am trying to stop the flagwave on mouseout but its not working. Once i mouseover it works but once i mouseout the mouseover action is looping its not stopping. Can i know whats the mistake i have done.
This is my js code:
elem.addEventListener("mouseout", mouseOut , false);
function mouseOut(event) {
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
clearBangladesh();
}
function clearBangladesh(){
canvas.clearRect(0,0,300, 150);
drawBangladesh();
}
THis is the code for the animation:
function waveFlag( canvas, wavelength, amplitude, period, shading, squeeze ){
if (!squeeze) squeeze = 0;
if (!shading) shading = 100;
if (!period) period = 200;
if (!amplitude) amplitude = 10;
if (!wavelength) wavelength = canvas.width/10;
var fps = 30;
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var od = ctx.getImageData(0,0,w,h).data;
// var ct = 0, st=new Date;
return setInterval(function(){
var id = ctx.getImageData(0,0,w,h);
var d = id.data;
var now = (new Date)/period;
for (var y=0;y<h;++y){
var lastO=0,shade=0;
var sq = (y-h/2)*squeeze;
for (var x=0;x<w;++x){
var px = (y*w + x)*4;
var pct = x/w;
var o = Math.sin(x/wavelength-now)*amplitude*pct;
var y2 = y + (o+sq*pct)<<0;
var opx = (y2*w + x)*4;
shade = (o-lastO)*shading;
d[px ] = od[opx ]+shade;
d[px+1] = od[opx+1]+shade;
d[px+2] = od[opx+2]+shade;
d[px+3] = od[opx+3];
lastO = o;
}
}
ctx.putImageData(id,0,0);
},1000/fps);
}
This is the mouseover function:
function mouseMove(event) {
var elem = document.getElementById('bangladesh-canvas');
var mouseX,
mouseY;
event.preventDefault(); // stops browser to do what it normally does
// determine where mouse is
mouseX = event.pageX;
mouseY = event.pageY;
// do something useful, e.g. change the flag to waving when mouse is over flag
waveFlag( elem, 50, 5, 200, 250, -0.1 );
}
Is this the rightway to stop an event on mouse out? Thanks in advance
Your waveFlag() animation function works by calling setInterval(), which queues up some code to be run at regular intervals forever - unless you cancel it or navigate away from the page. So how to cancel it? It returns an id. You need to call clearInterval() and pass that id, which means you need to actually store the id value in a variable as shown below.
Also, both your mouseover and mouseout handlers have a lot of unnecessary code that doesn't do anything: you create variables and assign values but never use those variables. And there is no need to call preventDefault() because neither event has default behaviour that needs cancelling. So, try something like this:
var intervalId;
function mouseMove(event) {
var elem = document.getElementById('bangladesh-canvas');
intervalId = waveFlag( elem, 50, 5, 200, 250, -0.1 );
}
function mouseOut(event) {
clearInterval(intervalId);
clearBangladesh();
}
Keep your existing calls to elem.addEventListener() as they are.
event.preventDefault() is the common way to stop an event's default behavior from occurring. Also, try e.stopPropagation(), in case your event is bubbling up anywhere else in your code. The final thing to attempt is returning false from the function.
However, you might need to show code related to drawBangladesh(), as that may be the cause of your continuous looping, and without it I can't say for certain that your issue is the event handler.
If you're not too keen on event handling, this MDN page may help: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/More_Event_Handlers#Prevent_Default_Action
I've been trying to develop a scratch card in EaselJS.
So far, I've managed to get a Shape instance above a Bitmap one and enabled erasing it with click and drag events, so the image below becomes visible.
I've used the updateCache() with the compositeOperation approach and it was easy enough, but here is my issue:
How can I find out how much the user has already erased from the Shape instance, so I can setup a callback function when, say, 90% of the image below is visible?
Here is a functioning example of what I'm pursuing: http://codecanyon.net/item/html5-scratch-card/full_screen_preview/8721110?ref=jqueryrain&ref=jqueryrain&clickthrough_id=471288428&redirect_back=true
This is my code so far:
function Lottery(stageId) {
this.Stage_constructor(stageId);
var self = this;
var isDrawing = false;
var x, y;
this.autoClear = true;
this.enableMouseOver();
self.on("stagemousedown", startDrawing);
self.on("stagemouseup", stopDrawing);
self.on("stagemousemove", draw);
var rectWidth = self.canvas.width;
var rectHeight = self.canvas.height;
// Image
var background = new createjs.Bitmap("http://www.taxjusticeblog.org/lottery.jpg");
self.addChild(background);
// Layer above image
var overlay = new createjs.Shape();
overlay.graphics
.f("#55BB55")
.r(0, 0, rectWidth, rectHeight);
self.addChild(overlay);
overlay.cache(0, 0, self.canvas.width, self.canvas.height);
// Cursor
self.brush = new createjs.Shape();
self.brush.graphics
.f("#DD1111")
.dc(0, 0, 5);
self.brush.cache(-10, -10, 25, 25);
self.cursor = "none";
self.addChild(self.brush);
function startDrawing(evt) {
x = evt.stageX-0.001;
y = evt.stageY-0.001;
isDrawing = true;
draw(evt);
};
function stopDrawing() {
isDrawing = false;
};
function draw(evt) {
self.brush.x = self.mouseX;
self.brush.y = self.mouseY;
if (!isDrawing) {
self.update();
return;
}
overlay.graphics.clear();
// Eraser line
overlay.graphics
.ss(15, 1)
.s("rgba(30,30,30,1)")
.mt(x, y)
.lt(evt.stageX, evt.stageY);
overlay.updateCache("destination-out");
x = evt.stageX;
y = evt.stageY;
self.update();
$rootScope.$broadcast("LotteryChangeEvent");
};
}
Any ideas?
That's a tricky one, regardless of the language. The naive solution would simply be to track the length of the paths the user "draws" within the active area, and then reveal when they scratch long enough. That's obviously not very accurate, but is fairly simple and might be good enough.
The more accurate approach would be to get the pixel data of the cacheCanvas, then check the alpha value of each pixel to get an idea of how many pixels are transparent (have low alpha). You could optimize this significantly by only checking every N pixel (ex. every 5th pixel in every 5th row would run 25X faster).
So, I have an <img> tag that has an onclick attribute. The onclick calls a function called analyze(this), with this being the image.
The analyze function does some things to the image that aren't entirely relevant, except for the fact that it draws it onto the <canvas> element (using the drawImage function).
But now, I want to also pick the color I just clicked on in the image. I am currently using the method answered here (the answer with 70+ votes, not the chosen one): How do I get the coordinates of a mouse click on a canvas element?
But, I think I might be doing this wrong. I have the image drawn and my functions called (and those all work), but the color picking part isn't being called. I think that this is because I didn't actually capture the event. This is generally how my code looks:
<img onclick="javascript:analyze(this);" />
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
img = new Image();
img.onload = function () {
canvaselement.drawImage(img, 0, 0, 250, 250);
...
canvaselement.onClick = function () {
var coords = canvaselement.relMouseCoords(event);
pick(img, canvaselement, coords); // pass in coordinates
}
}
img.src = img_elem.src;
}
function relMouseCoords(event) {
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasX = 0;
var canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX;
canvasY = event.pageY - totalOffsetY;
return {
x: canvasX,
y: canvasY
}
}
function pick(img, canvaselement, coords) {
var pickedColor = "";
canvaselement.drawImage(img, 0, 0, 250, 250);
xx = coords.x;
yy = coords.y;
var imgData = canvas.getImageData(xx, yy, 1, 1).data;
pickedColor = rgbToHex(imgData);
//alert(pickedColor);
return pickedColor;
}
So, the code never gets to the pick function. I have a feeling that it's because I didn't actually capture the onclick event. I'm also not even sure if this is the right way to get the coordinates on the canvas, I'm just sort of hoping that I even get to that part of the debugging process at this point.
Thanks for your help!
The problem is probably that you're assigning canvaselement to the results of getContext('2d') and not to the element itself, which you will need for the click event binding. Create two variables, one for the DOM element itself and one for the context, something like:
var canvaselement = document.getElementById('canvas'),
canvaselementctx = canvaselement.getContext('2d');
...
canvaselement.onClick = function() {
var coords = canvaselementctx.relMouseCoords(event);
...
}
You have a couple of errors in the code but the reason the code you got from the linked post is that you forgot to include the prototype definition it uses:
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
Now you can call relMouseCoords on the canvas element:
/// event name in lower case
canvaselement.onclick = function () {
var coords = canvaselement.relMouseCoords(event);
//...
However, you will still get problems as you don't use a canvas context for the drawing calls.
function analyze(img_elem) {
// This is getting the canvas from the page and the image in it
var canvaselement = document.getElementById('canvas').getContext('2d'),
/// get context like this
ctx = canvaselement.getContext('2d'),
img = new Image();
img.onload = function () {
/// use context to draw
ctx.drawImage(img, 0, 0, 250, 250);
//...
I create image in this way:
var orc = new Image();
orc.src = "./orc.png";
I use image in objects like this:
function Character(hp, image){
this.hp = hp;
this.image = image;
};
I call it in several times, like:
unit245 = new Character(100, orc);
And I draw it in this way, for example:
ctx.drawImage(unit245.image, 15, 55, 100, 100);
How I can get mouse click or move above my unit245 on canvas?
I need something like this http://easeljs.com/examples/dragAndDrop.html but without any frameworks (except jquery)
There is no built in way. I've written a few tutorials on making movable and selectable shapes on a Canvas to help people get started with this sort of thing though.
In short you need to remember what you have drawn and where, and then check each mouse click to see if you have clicked on something.
HitTesting can be done by checking what is present at the current location over the canvas, which can be called upon mouse click or move event over the canvas (which is the basis of hit testing). This can be done by knowing what has been placed where, like the bounds of an image can be saved, and when user clicks somewhere or moved the mouse over the canvas, you can check whether it is inside the image bounds or outside it. Array or List can be used for this.
Here is how this can be done
You cannot. The canvas has no semblance of what your unit245 or Character object is. You will have to actually manually check the coordinates and see if they fall within the bounds that you have for the character.
For example (assuming your Canvas is a var named canvas):
canvas.onclick = function(e) {
if (e.x >= unit245.x && e.x <= unit245.x + unit245.width && e.y >= unit245.y && e.y <= unit245.y + unit245.height) {
alert("You clicked unit245!");
}
}
In your case:
unit245.x = 15
unit245.y = 55
unit245.width = 100
unit245.height = 100
function Item(img, x, y){
this.image = img;
this.x = x;
this.y = y;
this.canv = document.createElement("canvas");
this.canv.width = this.image.width;
this.canv.height = this.image.height;
this.ctx = this.canv.getContext('2d');
this.ctx.drawImage(this.image, 0, 0, CELL_SIZE, CELL_SIZE);
this.hit = function (mx, my) {
var clr;
clr = this.ctx.getImageData(mx - this.x, my - this.y, 1, 1).data;
if (clr[3] > 250) {
//On object
this.image = gold_glow;
} else {
//Leave object
this.image = gold;
}
};
}