I'm trying to get my inputhandler to work in Javascript.
What
In my Game.update I currently have this code:
this.Update = function() {
if (input.GetMousePressed()) {
console.log(input.GetMousePosition());
}
}
And this is my inputhandler:
function InputHandler(canvas) {
this.canvas = canvas;
this.mousePressed = false;
this.mouseDown = false;
this.mousePosition = new Position(0, 0);
this.GetMousePosition = function() {
return this.mousePosition;
}
this.SetMousePosition = function(event) {
var rect = this.canvas.getBoundingClientRect();
this.mousePosition = new Position(event.clientX - rect.left, event.clientY - rect.top);
}
this.GetMousePressed = function() {
return this.mousePressed;
}
this.canvas.onmousedown = function(event) {
input.mouseDown = true;
input.SetMousePosition(event);
}
this.canvas.onclick = function(event) {
input.mouseClicked = true;
input.SetMousePosition(event);
}
window.onmouseup = function(event) {
if (input.mouseDown == true) {
input.mousePressed = true;
input.mouseDown = false;
}
}
The first problem is that I dont know how to handle mousePressed and set it to false. Now it stays true forever.
I'm quite new to Javascript and I'm thankful for any change that would make this better or cleaner code or if what Im doing is bad practice.
I'm using addEventListener for normal button pressing and maybe I should for this to?
Not sure why you need mousepressed/mouseup and click events. The only difference between successful pressed/up and click is that click target should be the same element.
So I would either use the first option or the last but not both.
Your mousePressed flag is set to true because it gets assigned true value once you press the mouse. You need to reset it back to false at some point.
Usually, you don't even need this flag since you trigger whatever function you need inside mousepressed event. Not sure why you would save the information that this happened, do you use it somewhere else?
Also, yes using addEventListener would be better.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
var imageWidth = 180;
var imageHeight = 160;
var canvas = null;
var ctx = null;
var mouseDown = false;
var mouseX = 0;
var mouseY = 0;
var bounds = null;
function canvas_onmousedown(e) {
mouseDown = true;
}
function canvas_onmousemove(e) {
if (mouseDown) {
mouseX = e.clientX - bounds.left;
mouseY = e.clientY - bounds.top;
}
}
function canvas_onmouseup(e) {
mouseDown = false;
}
function loop() {
ctx.fillStyle = "gray";
ctx.fillRect(0,0,imageWidth,imageHeight);
if (mouseDown) {
ctx.fillStyle = "yellow";
} else {
ctx.fillStyle = "black";
}
ctx.fillRect(mouseX - 25,mouseY - 25,50,50);
requestAnimationFrame(loop);
}
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.onmousedown = canvas_onmousedown;
canvas.onmousemove = canvas_onmousemove;
canvas.onmouseup = canvas_onmouseup;
ctx = canvas.getContext("2d");
bounds = canvas.getBoundingClientRect();
requestAnimationFrame(loop);
}
</script>
</body>
</html>
Related
i am trying to create an image canvas where user can zoom into the image, the code which i got from here enter link description here, now i tried to add image inside it and i did the following code:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base(context);
}
function make_base(context) {
var base_image = new Image();
base_image.src = 'https://www.gstatic.com/webp/gallery3/1.sm.png';
base_image.onload = function() {
context.drawImage(base_image, 0, 0);
}
}
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function() {
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function() {
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function() {
$("#wrapper").mouseover(function(e) {
$('#status').html(e.pageX + ', ' + e.pageY);
});
})
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type="button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
however the image is not getting displayed inside the canvas, can anyone please tell me what could be wrong in here, thanks in advance
Your draw function never actually draws to the canvas. You get the canvas and context in the first 2 lines, but you need to call drawImage with the image to actually add it to the canvas itself.
I suspect you want to be calling make_base inside it like so:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base();
}
You also need to have the context in the same scope as you use it. At the moment, the variable context only exists inside the draw function and not the make_base function, so you can't access it from inside make_base.
You can pass it as a variable like so:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base(context);
}
function make_base(context) {
var base_image = new Image();
base_image.src = 'a2.jpg';
base_image.onload = function() {
context.drawImage(base_image, 0, 0);
}
}
Every time you want to change anything on an HTML canvas you need to call draw functions to change what's there.
I'm looking for an automatic drag and dropper. First, when I click anywhere on the screen, get coordinates, then drag and drop an element with the ID of "ball". using jQuery OR javascript.
I coded a similar script to what I want, but this script got patched when the website's client got updated. This one automatically dragged and dropped when I pressed key 1(keycode 49),
(function () {
'use strict';
var mouseX = 0;
var mouseY = 0;
var invName = '';
var timer = 0;
document.body.addEventListener('mousemove', function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
$('.inventory-box').mousedown(function (e) {invName = e.currentTarget.id;});
function drop () {
$('#' + invName).trigger($.Event('mousedown', {button: 0}));
$('body').trigger($.Event('mouseup', {
button: 0,
clientX: mouseX,
clientY: mouseY
}));
timer = setTimeout(drop, 100);
}
window.addEventListener('keyup', function (e) {
if (e.keyCode == 49 && !timer) {
invName = 'ball';
drop();
setTimeout(function () {
(clearTimeout(timer), timer = 0);
}, 20);
}
});
})();
when I click anywhere on the screen, it gets it's coordinates, then drag and drops an element with the ID of "ball"
Here's a very simple vanilla JavaScript method that will locate an element with the ID of "ball" at the cursor location upon click.
The "ball" will follow the cursor until the next click, then the ball will be dropped at the click location.
const ball = document.getElementById('ball');
const ballHalfHeight = Math.round(ball.offsetHeight / 2);
const ballHalfWidth = Math.round(ball.offsetWidth / 2);
let dragState = false;
// move ball to position
function moveBallTo(x, y) {
ball.style.top = y - ballHalfHeight + 'px';
ball.style.left = x - ballHalfWidth + 'px';
}
// listen for 'mousemove' and drag ball
function dragListener(evt) {
const {clientX, clientY} = evt;
moveBallTo(clientX, clientY);
};
// respond to 'click' events (start or finish dragging)
window.addEventListener('click', (evt) => {
const {clientX, clientY} = evt;
moveBallTo(clientX, clientY);
ball.classList.remove('hidden');
// handle dragging
if (!dragState) {
window.addEventListener('mousemove', dragListener);
} else {
window.removeEventListener('mousemove', dragListener);
}
dragState = !dragState;
});
.div-ball {
position: fixed;
background-color: dodgerblue;
width: 2rem;
height: 2rem;
border-radius: 1rem;
}
.hidden {
opacity: 0;
}
<body>
<h4>Click anywhere</h4>
<div class="div-ball hidden" id="ball"></div>
</body>
Im trying to make the image of a trex jump when canavas is clicked
Here is my code
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<canvas onclick="canjump = true; renderer = requestAnimationFrame(loop); dinoy = 150;" height="250px" width="350px" style="border: 2px solid black" id="canvas"></canvas>
<img src="./dino.png" height="0px" width="0px" id="dinoimg">
<img src="./cacti.png" height="0px" width="0px" id="cactimg">
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
main.js
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var dinoimage = document.getElementById('dinoimg');
var dinoheight = 100;
var dinowidth = 50;
var dinox = 0;
var dinoy = 150;
var canjump = false;
var renderer;
var jmpv = 15;
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
function jumpdino() {
ctx.clearRect(0, 0, 350, 250);
ctx.drawImage(dinoimage, dinox, dinoy, dinowidth, dinoheight);
dinoy -= jmpv;
jmpv--;
}
The problem is that everything work as expected for first time but when canvas is clicked after then (second click and after), the image just go up and come down very fast and not smoothly with acceleration like first time.
Please help!!!
Those two fore function calls are commented because they arent implemented yet.
Just fixing the code you have I added a return in the else, the issue was even though you canceled the requestAnimationFrame after the else condition it still would continue and reassign renderer to the loop. So it was always running, each time you clicked it was just adding another instance making it go faster and faster.
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
// You need to exit out.
return;
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var dinoheight = 100;
var dinowidth = 50;
var dinox = 0;
var dinoy = 150;
var canjump = false;
var renderer;
var jmpv = 15;
function loop() {
if (canjump = true && dinoy <= 150) {
jumpdino();
} else {
dinoy = 151;
jmpv = 15;
canjump = false;
cancelAnimationFrame(renderer);
return;
}
//setcacti();
//checkcollision();
renderer = requestAnimationFrame(loop);
}
function jumpdino() {
ctx.clearRect(0, 0, 350, 250);
ctx.fillRect(dinox, dinoy, dinowidth, dinoheight);
dinoy -= jmpv;
jmpv--;
}
<canvas onclick="canjump = true; requestAnimationFrame(loop); dinoy = 150;" height="250px" width="350px" style="border: 2px solid black" id="canvas"></canvas>
Personally I'd remove the inline event handler and do something like this in your code as well.
canvas.addEventListener('click', () => {
canjump = true;
dinoy = 150;
loop();
});
I've got a main.js calling a CanvasConstructor Class, in this one I make my canvas and manage the mouse for signing onto the canvas with different methods. That works!
Now I wanted to add methods to use it on smartphones (using ontouch events).
I can get only one position, which is not the actual position of my finger.
The ontouchmove() doesn't change the position either.
I tried to get my canvas by getElementById(), the problem was the same.
I assume that I've got some problems with getting the different contexts within my Class, so it's one part of the global problem.
The second problem is how to manage the ontouch events correctly.
(Sorry for my English and my JS skills, I try my best).
index.html:
<canvas class="canvas-style" id="canvas" width="200" height="70"></canvas>
main.js:
const canvas = new CanvasConstructor();
canvas.mouseConstructor();
canvas.touchConstructor();
/* I usually comment one of them to test each other */
canvas.js:
class CanvasConstructor{
constructor(){
this.color = "#000";
this.painting = false;
this.started = false;
this.width_brush = 2;
this.canvas = $("#canvas");
this.cursorX; this.cursorY;
this.restoreCanvasArray = [];
this.restoreCanvasIndex = 0;
this.context = this.canvas[0].getContext('2d');
this.context.lineJoin = 'round';
this.context.lineCap = 'round';
}
mouseConstructor(){
var self = this;
this.canvas.mousedown(function(e) {
this.painting = true;
this.cursorX = (e.pageX - this.offsetLeft);
this.cursorY = (e.pageY - this.offsetTop);
});
this.canvas.mouseup(function() {
this.painting = false;
this.started = false;
});
this.canvas.mousemove(function(e) {
if (this.painting) {
this.cursorX = (e.pageX - this.offsetLeft) - 10;
this.cursorY = (e.pageY - this.offsetTop) - 10;
self.drawLine(this.cursorX, this.cursorY);
}
});
self.reset();
}
touchConstructor(){
var self = this;
this.canvas[0].addEventListener('touchstart', function(e) {
e.preventDefault();
this.painting = true;
console.log("touchSTART!!");
this.cursorX = (e.pageX - this.offsetLeft);
this.cursorY = (e.pageY - this.offsetTop);
}, false);
this.canvas[0].addEventListener('touchend', function(e) {
e.preventDefault();
this.painting = false;
this.started = false;
}, false);
this.canvas[0].addEventListener('touchmove', function(e) {
if (this.painting) {
e.preventDefault();
this.cursorX = (e.pageX - this.offsetLeft);
this.cursorY = (e.pageY - this.offsetTop);
self.drawLine(this.cursorX, this.cursorY);
}
}, false);
self.reset();
}
drawLine(cursorX, cursorY) {
if (!this.started) {
this.context.beginPath();
this.context.moveTo(cursorX, cursorY);
this.started = true;
}
else {
this.context.lineTo(cursorX, cursorY);
this.context.strokeStyle = this.color;
this.context.lineWidth = this.width_brush;
this.context.stroke();
}
}
clear_canvas() {
this.context.clearRect(0,0, this.canvas.width(), this.canvas.height());
}
reset(){
var self = this;
$("#reset").click(function() {
self.clear_canvas();
});
}
}
When you touch the canvas you get the ontouchstart(), onctouchend() and ontouchmove() functions, but it doesn't draw because I can't get the actual position of the touching.
Please explain me how to do it correctly.
I have update the touchConstructor function as follow.
touchConstructor(){
var self = this;
this.canvas[0].addEventListener('touchstart', function(e) {
e.preventDefault();
this.painting = true;
console.log("touchSTART!!");
var pageX = e.touches[0].pageX; //to get pageX value in touch devices
var pageY = e.touches[0].pageY; //to get pageY value in touch devices
this.cursorX = (pageX - this.offsetLeft);
this.cursorY = (pageY - this.offsetTop);
}, false);
this.canvas[0].addEventListener('touchend', function(e) {
e.preventDefault();
this.painting = false;
this.started = false;
}, false);
this.canvas[0].addEventListener('touchmove', function(e) {
if (this.painting) {
e.preventDefault();
var pageX = e.touches[0].pageX; //to get pageX value in touch devices
var pageY = e.touches[0].pageY; //to get pageY value in touch devices
this.cursorX = (pageX - this.offsetLeft);
this.cursorY = (pageY - this.offsetTop);
self.drawLine(this.cursorX, this.cursorY);
}
}, false);
self.reset();
}
I was trying to create a sample paint application using HTML 5 canvas. Then I added a button to redraw what user had drawn earlier. I am not sure what I am doing wrong or may be completely wrong. When I click redraw button multiple times it generates some magical animation by drawing lines all over. Even though if I log the starting point of drawing the image its same every time.
Demo: http://jsfiddle.net/BW57H/6/
Steps to reproduce:
Draw some circle or rectangle or something by clicking the mouse and dragging it on the rectangular box. Then click reset and redraw , click redraw couple of times after that and see the result.
I am not sure what I have done. I have not read a lot about Canvas. But I am curious to know what is going on here. Thanks.
html
<body>
<canvas id="paint" width="600px" height="300px"></canvas>
<div id="controls">
<button name="reset" id="reset">Reset</button>
<button name="redraw" id="redraw">Re-Draw</button>
</div>
</body>
css
#paint{
border: solid;
}
js
$(document).ready(function(){
var x, y, context, painter;
var xCounter = 0 , yCounter = 0;
var xarray = [];
var yarray = [];
function init(){
while(document.getElementById("paint") === undefined){
//do nothing
}
console.log("Loaded document now registering events for canvas");
var canvas = document.getElementById("paint");
context = canvas.getContext('2d');
painter = new Painter();
canvas.addEventListener('mousedown', capture, false);
canvas.addEventListener('mouseup', capture, false);
canvas.addEventListener('mousemove', capture, false);
document.getElementById("reset").addEventListener("click",function(){ clearCanvas(canvas);}, false);
document.getElementById("redraw").addEventListener("click", function(){
autoDraw();
}, false);
}
function clearCanvas(canvas){
context.save();
// Use the identity matrix while clearing the canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
context.restore();
};
function capture(event){
if(event.which !== 1){
return;
}
x = event.layerX;
y = event.layerY;
switch(event.type){
case 'mousedown':
painter.startPaint(event);
break;
case 'mouseup':
painter.endPaint(event);
break;
case 'mousemove':
painter.paint(event);
break;
}
};
var Painter = function(){
var self = this;
self.paintStarted = false;
self.startPaint = function(event){
self.resetRecordingParams();
self.paintStarted = true;
context.beginPath();
context.moveTo(x,y);
self.record();
}
self.endPaint = function(event){
self.paintStarted = false;
self.record();
self.paint(event)
}
self.paint = function(event){
if(self.paintStarted){
context.lineTo(x,y);
context.stroke();
self.record();
}
}
self.record = function(){
xarray[xCounter++] = x;
yarray[yCounter++] = y;
}
self.resetRecordingParams = function(){
xarray = [];
yarray = [];
xCounter = 0;
yCounter= 0;
}
return self;
}
function autoDraw(){
context.beginPath();
console.log('starting at: '+xarray[0]+','+yarray[0]);
context.moveTo(xarray[0],yarray[0]);
for (var i = 0; i < xarray.length; i++) {
setTimeout(drawLineSlowly, 1000+(i*20), i);
};
}
function drawLineSlowly(i)
{
context.lineTo(xarray[i],yarray[i]);
context.stroke();
}
init();
});
You don't have any kind of check to see whether or not you are already drawing, so here is your code with those changes commented, as well as the real-pixel-location fixes (http://jsfiddle.net/upgradellc/htJXy/1/):
$(document).ready(function(){
var x, y, context, painter, canvas;
var xCounter = 0 , yCounter = 0;
var xarray = [];
var yarray = [];
function init(){
while(document.getElementById("paint") === undefined){
//do nothing
}
console.log("Loaded document now registering events for canvas");
canvas = document.getElementById("paint");
context = canvas.getContext('2d');
painter = new Painter();
canvas.addEventListener('mousedown', capture, false);
canvas.addEventListener('mouseup', capture, false);
canvas.addEventListener('mousemove', capture, false);
document.getElementById("reset").addEventListener("click",function(){ clearCanvas(canvas);}, false);
document.getElementById("redraw").addEventListener("click", function(){
autoDraw();
}, false);
}
function clearCanvas(canvas){
context.save();
// Use the identity matrix while clearing the canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
context.restore();
};
function capture(event){
if(event.which !== 1){
return;
}
tempPos = getMousePos(canvas, event);
x = tempPos.x;
y = tempPos.y;
switch(event.type){
case 'mousedown':
painter.startPaint(event);
break;
case 'mouseup':
painter.endPaint(event);
break;
case 'mousemove':
painter.paint(event);
break;
}
};
var Painter = function(){
var self = this;
self.paintStarted = false;
//this keeps track of whether or not we are currently auto drawing
self.currentlyAutoDrawing = false;
self.startPaint = function(event){
self.resetRecordingParams();
self.paintStarted = true;
context.beginPath();
context.moveTo(x,y);
self.record();
}
self.endPaint = function(event){
self.paintStarted = false;
self.record();
self.paint(event);
}
self.paint = function(event){
if(self.paintStarted){
context.lineTo(x,y);
context.stroke();
self.record();
}
}
self.record = function(){
xarray[xCounter++] = x;
yarray[yCounter++] = y;
}
self.resetRecordingParams = function(){
xarray = [];
yarray = [];
xCounter = 0;
yCounter= 0;
}
return self;
}
function autoDraw(){
context.beginPath();
//If we are already auto-drawing, then we should just return instead of starting another drawing loop cycle
if(painter.currentlyAutoDrawing){
console.log("painter is already auto drawing");
return;
}
painter.currentlyAutoDrawing = true;
console.log('starting at: '+xarray[0]+','+yarray[0]);
context.moveTo(xarray[0],yarray[0]);
for (var i = 0; i < xarray.length; i++) {
setTimeout(drawLineSlowly, 1000+(i*20), i);
};
}
function drawLineSlowly(i)
{
//when we reach the last element in the array, update painter with the fact that autodrawing is now complete
if(xarray.length == i+1){
painter.currentlyAutoDrawing=false;
}
console.log(xarray.length+" "+i);
context.lineTo(xarray[i],yarray[i]);
context.stroke();
}
function getMousePos(canv, evt) {
var rect = canv.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
init();
});
Obviously you don't stop the previous timeout loop before you start a new...
Use setInterval instead of setTimeout, and clearInterval by next push. So I think the problem is not with the canvas, just with your redraw animation. Btw it is strange because there is some difference between the redraw and the original draw...
var drawInterval = null;
function autoDraw(){
if (drawInterval) {
//here your can reset the previous - still running - redraw
clearInterval(drawInterval);
}
context.beginPath();
console.log('starting at: '+xarray[0]+','+yarray[0]);
context.moveTo(xarray[0],yarray[0]);
var i=0;
setInterval(function (){
++i;
if (i<xarray.length)
drawLineSlowly(i);
else
clearInterval(drawInterval);
},20);
}
note:
There is still bug in the redraw, but at least it does not kill the browser...
Btw the strange "animation" is because you does not check by redraw if you are currently drawing or not, so you start draw and redraw together and they interfere... You have to stop redraw when you start drawing.