fabric.js - Ending free drawing mode while mouse is moving - javascript

I have an application that allows the user to draw in a fabric canvas for a limited period of time. After the time ends, I would like to end the drawing mode and save the drawing made as an image.
My problem is that if the time ends while the user is still drawing (dragging the mouse), the drawing will disappear (after clicking on the canvas again).
The below fiddle example shows the application I made, and the steps to produce the problem are:
Run the fiddle, and start drawing immediately.
After 3 seconds the timeout event will occur and the free drawing mode will be ended. And the drawing will stop.
Click on the canvas again and drag the mouse.
The drawing will disappear.
Code example:
var canvas = new fabric.Canvas("c",{backgroundColor : "#fff"});
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "green";
canvas.freeDrawingBrush.width = 4;
setTimeout(stop_drawing, 3000);
function stop_drawing() {
canvas.isDrawingMode = false;
}
Fiddle example:
https://jsfiddle.net/usaadi/808x5d20/1/

You could emulate what happens in the library:
_onMouseUpInDrawingMode: function(e) {
this._isCurrentlyDrawing = false;
if (this.clipTo) {
this.contextTop.restore();
}
this.freeDrawingBrush.onMouseUp();
this._handleEvent(e, 'up');
},
In your case, you have just to fire onMouseUp event, so your function stop_drawing will be:
function stop_drawing() {
canvas.isDrawingMode = false;
canvas.freeDrawingBrush.onMouseUp();
}
in our case onMouseUp will be:
/**
* Invoked on mouse up
*/
onMouseUp: function() {
this._finalizeAndAddPath();
},
let's see how it works _finalizeAndAddPath:
/**
* On mouseup after drawing the path on contextTop canvas
* we use the points captured to create an new fabric path object
* and add it to the fabric canvas.
*/
_finalizeAndAddPath: function() {
var ctx = this.canvas.contextTop;
ctx.closePath();
var pathData = this.convertPointsToSVGPath(this._points).join('');
if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {
// do not create 0 width/height paths, as they are
// rendered inconsistently across browsers
// Firefox 4, for example, renders a dot,
// whereas Chrome 10 renders nothing
this.canvas.renderAll();
return;
}
var path = this.createPath(pathData);
this.canvas.add(path);
path.setCoords();
this.canvas.clearContext(this.canvas.contextTop);
this._resetShadow();
this.canvas.renderAll();
// fire event 'path' created
this.canvas.fire('path:created', { path: path });
}
at this point the drawn path has already been added to the canvas.
I have updated your snippet here
if you want to take a look at the code below...
all the best
var canvas = new fabric.Canvas("c", {
backgroundColor: "#fff"
});
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.color = "green";
canvas.freeDrawingBrush.width = 4;
setTimeout(stop_drawing, 3000);
function stop_drawing() {
canvas.isDrawingMode = false;
canvas.freeDrawingBrush.onMouseUp();
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>

Related

Do DOM events work with pointer lock?

I have used the pointer lock on my canvas element, and the canvas is on full screen. I want to detect right clicks and left clicks to respond to them. Is it possible to respond to clicks in full screen and pointer lock? I already know how to use the pointer lock api and the fullscreen api, I don't want any answers explaining how to use them. Any help would be appreciated.
Based on the experiments I've done, the short answer is "it depends." Take a look at the following demo. There is a canvas scaled to be a quarter of the screen size in each dimension. When you move the cursor over it, a white circle appears on the canvas. When you left click, you'll draw a red circle to the canvas, and when you right click, you'll draw a cyan circle to the canvas. When you click the "Full screen" button, you'll activate pointer lock and enter fullscreen mode. If you press the "Esc" key, you'll exit pointer lock and fullscreen mode.
Note that you'll need to copy and paste the code into a file and load it. The demo won't run if you just click "Run code snippet."
As far as your question, there are two issues, I'm aware of:
In Chrome, both right- and left-click events are triggered even while in fullscreen/pointer lock. However, in Firefox, only left-click events are triggered; I was unable to get right-click events using any of the handlers I tried (click, mousedown, mouseup, contextmenu). When not in fullscreen/pointer lock, both left- and right-click events get triggered as expected in both browsers. If anyone has any solutions for listening to right-click events while in fullscreen/pointer lock, I'd love to hear them.
It seems that in pointer lock in both Chrome/Firefox, events no longer trickle down to elements contained in the element with pointer lock, but they continue to bubble up to parent elements. So in the demo, the canvas is inside a div. The div has pointer lock. onclick handlers are attached to the canvas, div, and document to report click events in the console. Without pointer lock, clicking on the canvas triggers onclick handlers for all three elements (canvas, div, and document). However, with pointer lock on the div, the onclick handler for the canvas never gets triggered, though the handlers for the div and the document do.
I also identified a couple other quirks to Firefox that, while not directly related to your initial question, might be helpful to folks interested in implementing this sort of thing:
When fullscreen mode is entered, Firefox will apply styles to the fullscreen element to get it to fill the screen. I was unable to get the canvas styled correctly (i.e. to take up the full screen) when it was placed full screen. Rather, I had to wrap the canvas in a div and enter full screen on the div. See the Fullscreen API documentation on MDN for more info:
if you're trying to emulate WebKit's behavior on Gecko, you need to place the element you want to present inside another element, which you'll make fullscreen instead, and use CSS rules to adjust the inner element to match the appearance you want.
In Firefox, activating fullscreen mode deactivated pointer lock. In order to get both activated, I had to first activate fullscreen mode and then activate pointer lock. However the simple two lines of code:
canvasContainer.requestFullscreen();
canvasContainer.requestPointerLock();
did not work. My understanding of what was happening is that the call to requestPointerLock got initiated before full screen mode was fully established. This led to pointer lock being activated and then quickly deactivated again. I found it necessary to wait until fullscreen mode was fully established before calling requestPointerLock(). Checking that document.mozFullScreenElement !== null seemed to be sufficient for checking that full screen mode was completely operational. The following following click handler definition worked to solve this problem for me:
document.getElementById('fullscreen_button').onclick = function(e) {
// When button is clicked, enter both full screen and pointer lock
canvasContainer.requestFullscreen();
var timeout = 2000;
var interval = window.setInterval(function() {
if (document.mozFullScreenElement !== null) {
window.clearInterval(interval);
canvasContainer.requestPointerLock();
} else if (timeout <= 0) {
addErrorMessage('Unable to establish pointer lock.');
clearTimeout(interval);
} else {
timeout -= 50;
}
}, 50);
}
This function repeatedly checks if full screen mode is established. When it is, it initiate pointer lock. If fullscreen mode can't be determined after 2 s, it times out.
I haven't done any testing in IE.
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<style>
</style>
</head>
<body>
<p id="msgs">Click 'Full screen' button below to go full screen. <br>
Click the left mouse button to draw a red circle. <br>
Click any other mouse button to draw a cyan circle. <br>
Press the 'Esc' key to exit full screen.</p>
<div id="canvas_container">
<canvas id="canvas"> </canvas>
</div>
<br>
<button id='fullscreen_button'>Full screen</button>
</body>
<script>
// Display constants
var CANVAS_BG_COLOR = 'rgb(75, 75, 75)';
var LEFT_CLICK_COLOR = 'rgb(255, 150, 150)';
var OTHER_CLICK_COLOR = 'rgb(150, 255, 255)';
var CURSOR_COLOR = 'rgb(200, 200, 200)';
var CANVAS_SCALING_FACTOR = 4; // Ratio between screen dimension and canvas dimension before going full-screen
// Store mouse position
var mouseX, mouseY;
// Setup onscreen canvas, smaller than the screen by a factor of CANVAS_SCALING_FACTOR
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = screen.width/CANVAS_SCALING_FACTOR;
canvas.height = screen.height/CANVAS_SCALING_FACTOR;
// Create an offscreen canvas that's the same as the size of the screen
var offscreenCanvas = document.createElement('canvas');
var offscreenCtx = offscreenCanvas.getContext('2d');
offscreenCanvas.width = screen.width;
offscreenCanvas.height = screen.height;
var canvasContainer = document.getElementById('canvas_container');
// Radius of the circle drawn and of the circle cursor
var circleRadius = 12;
var cursorRadius = circleRadius/CANVAS_SCALING_FACTOR
offscreenCtx.drawCircle = ctx.drawCircle = function (x, y, color, radius) {
this.fillStyle = color;
this.beginPath();
this.arc(x, y, radius, 0, 2*Math.PI, true);
this.fill();
}
offscreenCtx.clearCanvas = function() {
this.fillStyle = CANVAS_BG_COLOR;
this.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
ctx.update = function() {
// Copy the offscreen canvas, scaling down if not in full-screen mode
this.drawImage(offscreenCanvas, 0, 0, offscreenCanvas.width, offscreenCanvas.height,
0, 0, canvas.width, canvas.height);
// Draw the cursor
this.drawCircle(mouseX, mouseY, CURSOR_COLOR, cursorRadius);
}
function pointerLockActive() {
return document.pointerLockElement===canvasContainer || document.mozPointerLockElement === canvasContainer;
}
// Perform initial canvas setup
offscreenCtx.clearCanvas();
ctx.update();
// Setup pointerlock and fullscreen API functions for cross-browser support
function addErrorMessage(msg) {
document.getElementById('msgs').innerHTML += ('<br><font color="red">' + msg + '</font>');
}
canvasContainer.requestPointerLock = canvasContainer.requestPointerLock || canvasContainer.mozRequestPointerLock;
canvasContainer.requestFullscreen = canvasContainer.webkitRequestFullscreen || canvasContainer.mozRequestFullScreen || canvasContainer.msRequestFullscreen
if (!canvasContainer.requestPointerLock) addErrorMessage('Error: Pointer lock not available');
if (!canvasContainer.requestFullscreen) addErrorMessage('Error: Full screen mode not available');
canvasContainer.addEventListener('mousemove', function(e) {
if (pointerLockActive()) {
// If in pointer lock, then cursor positions need to be updated manually;
// Normal cursor positions (e.g. e.clientX and e.clientY) don't get updated in pointer lock
mouseX += e.movementX, mouseY += e.movementY;
// Prevent the mouse from moving off-screen
mouseX = Math.min(Math.max(0, mouseX), canvas.width);
mouseY = Math.min(Math.max(0, mouseY), canvas.height);
} else {
// If pointer lock is inactive, then mouse position is just position relative to canvas offset
mouseX = (e.pageX - canvas.offsetLeft)
mouseY = (e.pageY - canvas.offsetTop)
}
ctx.update(); // Update the onscreen canvas
}, false);
// Handle entering and exiting pointer lock; pointer lock status is yoked to full screen status; both are entered and exited at the same time
document.addEventListener('pointerlockchange', function(e) {
if (!pointerLockActive()) {
console.log('Pointer lock deactivated');
canvas.width /= CANVAS_SCALING_FACTOR;
canvas.height /= CANVAS_SCALING_FACTOR
cursorRadius /= CANVAS_SCALING_FACTOR;
} else {
console.log('Pointer lock activated')
canvas.width *= CANVAS_SCALING_FACTOR;
canvas.height *= CANVAS_SCALING_FACTOR;
cursorRadius *= CANVAS_SCALING_FACTOR;
// Set the initial mouse position to be the middle of the canvas
mouseX = screen.width/2, mouseY = screen.height/2;
}
// Update the onscreen canvas
ctx.update();
});
document.getElementById('fullscreen_button').onclick = function(e) {
// When button is clicked, enter both full screen and pointer lock
canvasContainer.requestFullscreen();
var timeout = 2000;
var interval = window.setInterval(function() {
if (document.mozFullScreenElement !== null) {
window.clearInterval(interval);
canvasContainer.requestPointerLock();
} else if (timeout <= 0) {
addErrorMessage('Unable to establish pointer lock.');
clearTimeout(interval);
} else {
timeout -= 50;
}
}, 50);
}
canvasContainer.onclick = function(e) {
console.log('canvasContainer clicked');
if (pointerLockActive())
// If pointer lock is active, then use the mouseX and mouseY positions that are manually updated by the mousemove event handler
var cursorX = mouseX, cursorY = mouseY;
else
// Otherwise use the mouse positions passed in the event object
// If not in full screen mode, the cursor position has to be scaled up, because the mouse position is relative to the onscreen canvas, but we're drawing on the offscreen canvas, which is larger by a factor of fullscreenScale
var cursorX = (e.pageX - canvas.offsetLeft)*CANVAS_SCALING_FACTOR, cursorY = (e.pageY - canvas.offsetTop)*CANVAS_SCALING_FACTOR;
// If the left mouse button is clicked (e.which===1), draw a circle of one color
// If any other mouse button is clicked, draw a circle of another color
var color = e.which === 1 ? LEFT_CLICK_COLOR : OTHER_CLICK_COLOR;
offscreenCtx.drawCircle(cursorX, cursorY, color, circleRadius);
ctx.update();
};
// Detect canvas right-click events. Prevent default behavior (e.g. context menu display) and pass on to the onclick handler to do the rest of the work
canvasContainer.oncontextmenu = function(e) {
e.preventDefault();
this.onclick(e);
}
canvas.onclick = function() {
console.log('canvas clicked');
}
document.onclick = function() {
console.log('document clicked');
}
</script>
</html>
This worked for me to handle rightClick after pointer was locked.
const onMouseDown = (evt) => {
switch (evt.which) {
case 1: return handleLeftClick();
case 3: return handleRightClick();
}
};
document.body.addEventListener('mousedown', onMouseDown, true);

Why wont my sprite appear on top of my background?

I have been practicing using sprites for a game I am going to make and have watched and read a few tutorials, I thought I was close to getting my sprite to appear so I could finally start my game but while practicing I cant get it to work, I have dont 2 seperate tutorials where I can get the sprite and the background to appear by themselfs but cannot get them to work together, I have been using EaselJS too. some of the sprite animation code has been copied from tutorials too.
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>sprite prac<title>
<!-- EaselJS library -->
<script src="lib/easel.js"></script>
<script>
// Initialize on start up so game runs smoothly
function init() {
canvas = document.getElementById("canvas");
stage = new Stage(canvas);
bg = new Image();
bg.src = "img/grassbg.jpg";
bg.onload = setBG;
stage.addChild(background);
imgMonsterARun = new Image();
imgMonsterARun.onload = handleImageLoad;
imgMonsterARun.onerror = handleImageError;
imgMonsterARun.src = "img/MonsterARun.png";
stage.update();
}
function handleImageLoad(e) {
startGame();
}
// Simple function for setting up the background
function setBG(event){
var bgrnd = new Bitmap(bg);
stage.addChild(bgrnd);
stage.update();
}
function startGame() {
// create a new stage and point it at our canvas:
stage = new createjs.Stage(canvas);
// grab canvas width and height for later calculations:
screen_width = canvas.width;
screen_height = canvas.height;
// create spritesheet and assign the associated data.
var spriteSheet = new createjs.SpriteSheet({
// image to use
images: [imgMonsterARun],
// width, height & registration point of each sprite
frames: {width: 64, height: 64, regX: 32, regY: 32},
animations: {
walk: [0, 9, "walk"]
}
});
// create a BitmapAnimation instance to display and play back the sprite sheet:
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
// start playing the first sequence:
bmpAnimation.gotoAndPlay("walk"); //animate
// set up a shadow. Note that shadows are ridiculously expensive. You could display hundreds
// of animated rats if you disabled the shadow.
bmpAnimation.shadow = new createjs.Shadow("#454", 0, 5, 4);
bmpAnimation.name = "monster1";
bmpAnimation.direction = 90;
bmpAnimation.vX = 4;
bmpAnimation.x = 16;
bmpAnimation.y = 32;
// have each monster start at a specific frame
bmpAnimation.currentFrame = 0;
stage.addChild(bmpAnimation);
// we want to do some work before we update the canvas,
// otherwise we could use Ticker.addListener(stage);
createjs.Ticker.addListener(window);
createjs.Ticker.useRAF = true;
createjs.Ticker.setFPS(60);
}
//called if there is an error loading the image (usually due to a 404)
function handleImageError(e) {
console.log("Error Loading Image : " + e.target.src);
}
function tick() {
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpAnimation.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpAnimation.direction = -90;
}
if (bmpAnimation.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpAnimation.direction = 90;
}
// Moving the sprite based on the direction & the speed
if (bmpAnimation.direction == 90) {
bmpAnimation.x += bmpAnimation.vX;
}
else {
bmpAnimation.x -= bmpAnimation.vX;
}
// update the stage:
stage.update();
}
</script>
</head>
<body onload="init();">
<canvas id="canvas" width="500" height="500" style="border: thin black solid;" ></canvas>
</body>
</html>
There are a few places where you are using some really old APIs, which may or may not be supported depending on your version of EaselJS. Where did you get the easel.js script you reference?
Assuming you have a version of EaselJS that matches the APIs you are using, there are a few issues:
You add background to the stage. There is no background, so you are probably getting an error when you add it. You already add bgrnd in the setBackground method, which should be fine. If you get an error here, then this could be your main issue.
You don't need to update the stage any time you add something, just when you want the stage to "refresh". In your code, you update after setting the background, and again immediately at the end of your init(). These will fire one after the other.
Are you getting errors in your console? That would be a good place to start debugging. I would also recommend posting code if you can to show an actual demo if you continue to have issues, which will help identify what is happening.
If you have a newer version of EaselJS:
BitmapAnimation is now Sprite, and doesn't support direction. To flip Sprites, use scaleX=-1
Ticker no longer uses addListener. Instead it uses the EventDispatcher. createjs.Ticker.addEventListener("tick", tickFunction);
You can get new versions of the CreateJS libraries at http://code.createjs.com, and you can get updated examples and code on the website and GitHub.

html5 canvas drawing: fast motion with mouse cancels line before it hits the edge of the canvas

The app works fine so far except if the line is drawn really fast and leaves the edge of the canvas, the line is then not drawn to the edge of the canvas. There is a part missing from it.
I'm trying to fix the issue with:
canvasVar.addEventListener ('mouseout', clearPathIfMouseCursorLeavesCanvasFunc);
and
function clearPathIfMouseCursorLeavesCanvasFunc(e){
contextVar.beginPath(); // clears the path so buttonpresses dont connect the line
mouseButtonHeld = false;
I've tried some things like adding a settimeout(); but nothing worked so far. I don't know what causes this and I've been searching if someone else had this problem and a fix for it, but every canvas drawing app I've come across has the same issues.
It's very important that the line is drawn to the edge and that the users mouse motion is recognized, not just a line to the last coordinates where the mouse left the canvas.
It's been days now that I'm stuck with this problem. Help is really appreciated!
Whole Code:
// Varibale declaration
var canvasVar = document.getElementById('canvasHtmlElement');
var contextVar = canvasVar.getContext('2d');
var pointRadiusVar = 0.5;
var mouseButtonHeld = false;
var pointsArrPosition = 0;
//Arrays
var pointsArr = [];
// Varibale declration end
//canvas setup
canvasVar.width = window.innerWidth;
canvasVar.height = window.innerHeight;
//canvas setup end
//resize fix
window.onresize = function() {
var tempImageVar = contextVar.getImageData(0, 0, canvasVar.width, canvasVar.height);
canvasVar.width = window.innerWidth;
canvasVar.height = window.innerHeight;
contextVar.putImageData(tempImageVar, 0, 0);
}
//resize fix end
//functions
// Objects
function pointObject() {
this.x = 0;
this.y = 0;
this.fill = '#444444';
}
function addFilledCircleFunc(x, y) {
//alert('works1');
var filledCircle = new pointObject;
filledCircle.x = x;
filledCircle.y = y;
pointsArr.push(filledCircle);
contextVar.lineWidth = 10; //pointRadiusVar * 2; // Line Width
contextVar.lineTo(pointsArr[pointsArrPosition].x, pointsArr[pointsArrPosition].y);
contextVar.stroke();
//contextVar.beginPath();
contextVar.fillRect(filledCircle.x, filledCircle.y, 1, 1);
//contextVar.arc(filledCircle.x, filledCircle.y, pointRadiusVar, 0, Math.PI * 2);
//contextVar.fill();
//contextVar.lineWidth = 0.5;
//contextVar.stroke();
//contextVar.beginPath();
pointsArrPosition++;
//contextVar.moveTo(pointsArr[pointsArrPosition].x, pointsArr[pointsArrPosition].y);
//alert(pointsArr[0].x);
}
//Objects end
// create circle on mouse clicked point while mousebutton is held
var addPointToCanvasVar = function(e) {
if (mouseButtonHeld) {
//alert('addpointfunc');
addFilledCircleFunc(e.clientX, e.clientY);
}
};
// MAKE SURE that lines work when drawn over the edge of the canvas
function clearPathIfMouseCursorLeavesCanvasFunc(e) {
contextVar.beginPath(); // clears the path so buttonpresses dont connect the line
mouseButtonHeld = false;
}
// end
// mouse Up/Down functions
var mouseDownVar = function(e) {
//alert("mouseDown");
addPointToCanvasVar(e); // add point on first click, not just when mousebutton is held
mouseButtonHeld = true;
}
var mouseUpVar = function() {
//alert("mouseUp");
mouseButtonHeld = false;
contextVar.beginPath(); // clears the path so buttonpresses dont connect the line
}
// mouse Up/Down Switch end
//functions end
//listeners
canvasVar.addEventListener('mousemove', addPointToCanvasVar);
canvasVar.addEventListener('mouseup', mouseUpVar);
canvasVar.addEventListener('mousedown', mouseDownVar);
canvasVar.addEventListener('mouseout', clearPathIfMouseCursorLeavesCanvasFunc);
//listeners end
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Confident Drawing</title>
</head>
<body style="margin: 0">
<canvas id="canvasHtmlElement" style="display: block;">
Your Browser does not support Canvas! Please update to a newer version.
</canvas>
<script src="main_0.06.js"></script>
</body>
</html>
If you don't get what I mean: Run the snippet and draw a line as fast as you can while exiting the canvas.
The reason the line ends prematurely near the edge when you quickly draw a line across the edge is because the last mousemove event fired when the mouse was still in the canvas and just short of the edge, and the very next mousemove event fired after your mouse left the canvas. To fix that problem, simply draw your line from the last recorded mouse position in the canvas to the one outside of the canvas as soon as the mouseout event fires.
You can add a new global variable mousePosition and initialize it to {x:0,y:0}. Every time mousemove fires (whenever you call addPointToCanvasVar), record the e.clientX and e.clientY to your mousePosition. Then when mouseout fires (whenever you call clearPathIfMouseCursorLeavesCanvasFunc), draw the rest of the line from mousePosition to the current e.clientX and e.clientY position. This will complete the line to the end of the canvas edge.

Javascript- canvas shooting positioning

I want to make a spaceship shoot in a game I am making, but I dont seem to be able to get the positions of the shots to load properly.
I have an array called shots[] and I want to push Shot() objects into it every N ticks when the player is holding down the mouse button.
So basically I want Shot() have x property equal to my ship.x property and y=ship.y.
Then I want it to have a Shot.dx property, which changes, depending on wether the cursor is above the middle of canvas or bellow (+3/-3) or left or right of the center (dy=+3/-3).
// Shooting
var shots = [] //Bullet array
//Object, which should be the position of the bullet.
function Shot() {
this.x=350
this.y=250;
this.dx=Shoot.x
this.dy=Shoot.y
}
//This keeps track of the cursor position in relation to the center of canvas.
function Shoot() {
started = false;
this.mousedown = function (ev) {
started = true;
};
this.mousemove = function (ev) {
if (started) {
if (ev.clientX>=350) this.x=3;
else this.x=-3;
if (ev.clientY>=250) this.y=3;
else this.y=-3;
}
};
this.mouseup = function (ev) {
started = false;
};
}
//The problem is, that when I set this.x in Shot() to be =ship.x the values
//dont get updated and it stays undefined after I push it into the array.
//Now I have it set to the center of canvas, but that it useless because it needs
//to move with the ship, but even now I am getting weird numbers and not the numbers
//that I actually put in. dx and dy dont get updated at all.
// Ship Model
var ship = {
x: 350,
y: 250,
lives: 3,
invulnerable: 0,
}
//Main function- pushes the objects into the array
function mainLoop() {
tick++
count()
interval()
chase()
console.log(started)
if (started && tick%20==0)
shots.push(new Shot());
keyboard()
display()
check()
requestAnimationFrame(mainLoop);
}
// Initialization
window.onload = function() {
// Setting variables
button = document.getElementById("button")
text = document.getElementById("text")
canvas = document.getElementById("canvas")
ctx = canvas.getContext("2d")
weapon = new Shoot();
canvas.onmousedown = weapon.mousedown;
canvas.onmousemove = weapon.mousemove;
canvas.onmouseup = weapon.mouseup;
requestAnimationFrame(mainLoop);
}
//I know this is a lot of code, but its all relevant. I am new to Javascript
//so I expect this to be some sort of a trivial error.
Here is a JSfiddle, but I dont know how that works so I cant get it to draw canvas, sorry: http://jsfiddle.net/JH3M6/
Here's an outline of how to fire your shots:
create an array to hold your shot objects
on mousedown: set the started flag (starts firing)
on mousedown: set the firing position for any new shot(s) to the current mouse position
on mousemove: reset the firing position for any new shot(s) to the current mouse position
on mouseup: clear the started flag (stops firing)
In the animation loop:
add a shot at the current firing position if the mouse is still down
move all shots by their dx,dy
remove any shots from the shots[] array if the shot has moved off-canvas
clear the screen and draw the shots in their new positions
A Demo: http://jsfiddle.net/m1erickson/2f9sf/
Here's example code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// canvas related vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var bb=canvas.getBoundingClientRect();
var offsetX=bb.left;
var offsetY=bb.top;
ctx.fillStyle="blue";
// vars related to firing position and Shot(s)
var shotColor=ctx.fillStyle;
var started,mouseX,mouseY,dx,dy;
// Shots fired
var shots = [] //Bullet array
//Object, which should be the position of the bullet.
function Shot(x,y,dx,dy) {
this.x=x;
this.y=y;
this.dx=dx;
this.dy=dy;
}
Shot.prototype.display=function(){
// make fillstyle blue if it's not already blue
if(!ctx.fillStyle==shotColor){ctx.fillStyle=shotColor;}
// draw the shot on the canvas
ctx.fillRect(this.x,this.y,5,5);
}
// listen for mouse events
canvas.onmousedown=function(e){ started=true; setFirePosition(e); }
canvas.onmouseup=function(e){ started=false; }
canvas.onmousemove=function(e){
if(started){setFirePosition(e);}
}
// start the animation loop
requestAnimationFrame(animate);
// set the firing position of the next shot
function setFirePosition(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
dx=(mouseX>=canvas.width/2)?-3:3;
dy=(mouseY>=canvas.height/2)?-3:3;
}
// animation loop
// add shots if the mouse is down
// move shots until they move off-canvas
function animate(){
// request another frame
requestAnimationFrame(animate);
// if the mouse is down, add a shot
if(started){
shots.push(new Shot(mouseX,mouseY,dx,dy));
}
// if no work to do, return
if(shots.length==0){return;}
// new array of active shots
// "active" == shot has not moved off-canvas
var a=[];
// clear the canvas for this frame
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shots.length;i++){
// get a shot to process
var shot=shots[i];
// move this shot
shot.x+=shot.dx;
shot.y+=shot.dy;
// if the shot hasn't moved offscreen
// add the shot to "a" (the replacement shots array);
// draw this shot
if(shot.x>=0 && shot.x<=cw && shot.y>0 && shot.y<=ch){
a.push(shot);
shot.display();
}
}
// if shots went off-canvas, remove them from shots[]
if(a.length<shots.length){
shots.length=0;
Array.prototype.push.apply(shots,a);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Mousedown to fire shots</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Canvas Drawing Application Wont Work in Firefox

I'm working on this little drawing application type thing, but it won't work in Firefox. It works fine in chrome though. Here's the javascript, then I just have a regular old canvas element in HTML. Any help is appreciated!
/* FOR THE DRAWING APPLICATION */
/* =========================== */
var canvasMouse, contextMouse;
var started = false;
var x, y;
function initMouse() {
// Get the drawing canvas
canvasMouse = document.getElementById('drawing');
contextMouse = canvasMouse.getContext('2d');
// Add some event listeners so we can figure out what's happening
// and run a few functions when they are executed.
canvasMouse.addEventListener('mousemove', mousemovement, false);
canvasMouse.addEventListener('mousedown', mouseclick, false);
canvasMouse.addEventListener('mouseup', mouseunclick, false);
}
function mouseclick() {
// When the mouse is clicked. Change started to true and move
// the initial position to the position of the mouse
contextMouse.beginPath();
contextMouse.moveTo(x, y);
started = true;
}
function mousemovement(e) {
// Get moust position
x = e.offsetX;
y = e.offsetY;
// If started is true, then draw a line
if(started) {
contextMouse.lineTo(x, y);
contextMouse.stroke();
}
}
function mouseunclick() {
// Change started to false when the user unclicks the mouse
if(started) {
started = false;
}
}
Any ideas?
offsetX and offsetY are not supported in firefox (see compatibility table here). Instead you need to use layerX and layerY.
The following will work in firefox (see fiddle):
/* FOR THE DRAWING APPLICATION */
/* =========================== */
var canvasMouse, contextMouse;
var started = false;
var x, y;
function initMouse() {
// Get the drawing canvas
canvasMouse = document.getElementById('drawing');
contextMouse = canvasMouse.getContext('2d');
// Add some event listeners so we can figure out what's happening
// and run a few functions when they are executed.
canvasMouse.addEventListener('mousemove', mousemovement, false);
canvasMouse.addEventListener('mousedown', mouseclick, false);
canvasMouse.addEventListener('mouseup', mouseunclick, false);
}
function mouseclick(e) {
// When the mouse is clicked. Change started to true and move
// the initial position to the position of the mouse
// Get moust position
x = e.layerX;
y = e.layerY;
console.log("coords", x, y);
contextMouse.beginPath();
contextMouse.moveTo(x, y);
started = true;
}
function mousemovement(e) {
// Get mouset position
x = e.layerX;
y = e.layerY;
console.log("coords", x, y);
// If started is true, then draw a line
if(started) {
contextMouse.lineTo(x, y);
contextMouse.stroke();
}
}
function mouseunclick() {
// Change started to false when the user unclicks the mouse
if(started) {
started = false;
}
}
initMouse();
If you want to avoid browser specific conditional code and / or your canvas element is offset within the DOM hierarchy (read the limitations of layerX and layerY in the compatibility table linked to above), there may be an argument for using jQuery and its position() method.

Categories