I'm currently undergoing the development of a game, but I've stumbled across a problem where the fillRect() command will not work onto the HTML5 canvas, using Javascript. I do not know why this is happening, after trying to do research on it and checking my code. The HTML code is shown below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Cube Quest</title>
<style>
#game {
border: 1px dashed black;
}
</style>
</head>
<body>
<canvas id="game" width='1280' height='720'>Your browser does not support the canvas element in HTML5.</canvas>
<script>
var clicked = false; // Mouse handling event
var mouseX = event.cilentX; // Mouse X coordinate
var mouseY = event.cilentY; // Mouse Y coordinate
var canvas = document.getElementById("game"); // For canvas
var ctx = canvas.getContext("2d"); // For canvas
ctx.fillStyle = 'black'; // rectangle color selection
ctx.fillRect(10, 10, 150, 80);
</script>
</body>
</html>
I'm not the best expert on Javascript, so there is little that I know which could help me understand the reason why no rectangle shows when the code is correct.
I appreciate the help on this specific question in advance. :)
You will need to look addEventListener function in JS to made better view of situation.
Here working example :
// globals
var canvas = document.getElementById("game");
var clicked = false; // Mouse handling event
var mouseX = 0;
var mouseY = 0;
// yuor application parameters
var app = {
clearCanvas: true,
title: 'HELLO'
};
canvas.addEventListener('click' , function (event){
mouseX = event.pageX; // Mouse X coordinate
mouseY = event.pageY; // Mouse Y coordinate
console.log("Mouse x : " + mouseX + " Mouse y :" + mouseY );
drawAgain();
});
// Initial draw
var ctx = canvas.getContext("2d"); // For canvas
ctx.fillStyle = 'black'; // rectangle color selection
ctx.fillRect(mouseX, mouseY, 350, 65);
ctx.font="30px Arial";
ctx.fillStyle = 'lime';
ctx.fillText(app.title + "X:" + mouseX + " Y:" + mouseY , mouseX + 35, mouseY + 40, 250)
// Draw when you need
function drawAgain () {
if (app.clearCanvas == true){
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
ctx.fillStyle = 'black'; // rectangle color selection
ctx.fillRect(mouseX, mouseY, 350, 65);
ctx.fillStyle = 'lime';
ctx.fillText(app.title + " X:" + mouseX + " Y:" + mouseY , mouseX + 35, mouseY + 40, 400)
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Cube Quest</title>
<style>
#game {
border: 1px dashed black;
}
</style>
</head>
<body>
<canvas id="game" width='1280' height='720'>Your browser does not support the canvas element in HTML5.</canvas>
<script>
</script>
</body>
</html>
Suggestion: Also learn to use removeEventListener , lot of web
developers have trouble with event conflict situation when they use
lot of lib's. For dynamic app flow methodology use removeEventListener
before setting a flags.
Having error in event.cilentX because event is not available at this moment so that is not moving to next lines of code to execute. If you want to play with event you need to attache any event listener like canvas.addEventListener('click' , function (event){//here you will get the event});. I just commented the two line now it working fine to draw rectangle.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Cube Quest</title>
<style>
#game {
border: 1px dashed black;
}
</style>
</head>
<body>
<canvas id="game" width='1280' height='720'>Your browser does not support the canvas element in HTML5.</canvas>
<script>
var clicked = false; // Mouse handling event
// var mouseX = event.cilentX; // Mouse X coordinate
// var mouseY = event.cilentY; // Mouse Y coordinate
var canvas = document.getElementById("game"); // For canvas
var ctx = canvas.getContext("2d"); // For canvas
ctx.fillStyle = 'black'; // rectangle color selection
ctx.fillRect(10, 10, 150, 80);
</script>
</body>
</html>
It's your mouse event listeners that are breaking the program.
Comment them out and it works just fine.
Here is a code snippet I use for small JavaScript games I test out.
//Mouse Events ==================
document.onmousemove = mousePos;
document.onmousedown = function() { mouse.clicked = true; };
document.onmouseup = function() { mouse.clicked = false; };
//MOUSE
var mouse = {
x: 0,
y: 0,
clicked: false
};
function mousePos (e) {
mouse.x = e.pageX - canvas.offsetLeft;
mouse.y = e.pageY - canvas.offsetTop;
}
Related
At work, they needed a quick and dirty example to hand-sign a document and append it to JSON as a base64 Data URL. It works all fine and dandy in itself, but my own curiosity got the better of me and I was annoyed to find out, that the area of the buttons appeared to be much larger on mobile than they looked like. But even inspecting buttons in my example project didn't help me a lot to pin down the problems.
Disclaimer: I have to also point out, for people who look for a similar solution to NOT just copy-paste this example here. It's serviceable and works probably in 99% of the cases just fine for this purpose, but the drawing is not optimal. Why? Because I keep adding points indefinitely as long as the finger touches the canvas... and with each move, it goes through the array and REDRAWS all the lines! It becomes pretty noticeable after you covered a fair portion of the small canvas. It would be more elegant to go through the tracked points and kick them out of the array once drawn and not only when we raise the finger from the touchscreen. But if you merely use it to sign something like in my example, the example should be perfectly serviceable with no frills.
I did add a snippet as well. Don't forget, it's only working on mobile browsers or if you use emulation on your chrome browser, for example.
"use strict";
const canvas = document.getElementById('sign');
const context = canvas.getContext('2d');
context.lineCap = 'round';
context.lineJoin = 'round';
context.strokeStyle = 'black';
context.lineWidth = 2;
let points = [];
let isPainting = false;
setup();
function setup() {
if (isMobile() || isIpad()) {
setupMobile();
} else {
// Some other stuff that was supposed to happen, but was canned
return;
}
}
function setupMobile() {
canvas.addEventListener('touchstart', (e) => {
addToDrawingPointsTouch(canvas, e);
if (!isPainting) {
isPainting = !isPainting;
}
const ctx = context;
// Not the most elegant solution for the initial call, but touchmove takes a bit to trigger
const initialStarting = points[0];
ctx.beginPath();
ctx.moveTo(initialStarting.x, initialStarting.y);
ctx.lineTo(initialStarting.x, initialStarting.y);
ctx.stroke();
}, { passive: true })
canvas.addEventListener('touchmove', (e) => {
if (isPainting) {
addToDrawingPointsTouch(canvas, e);
const ctx = context;
points.forEach((v, index) => {
if (points[index + 1]) {
ctx.beginPath();
ctx.moveTo(v.x, v.y);
ctx.lineTo(points[index + 1]?.x, points[index + 1]?.y);
ctx.stroke();
}
})
}
}, { passive: true })
canvas.addEventListener('touchend', () => {
if (isPainting) {
isPainting = !isPainting;
points = [];
}
}, { passive: true })
}
function addToDrawingPointsTouch(canvas, mouseEvent) {
const rect = canvas.getBoundingClientRect();
points.push({
x: (mouseEvent.touches[0].clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (mouseEvent.touches[0].clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
});
}
function isMobile() {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
return true
} else {
return false;
}
}
function isIpad() {
if (navigator.userAgent.match(/Mac/) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2) {
return true;
}
else {
false;
}
}
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function createCanvasPngDataUrl() {
return canvas.toDataURL('image/png');
}
body {
user-select: none;
-webkit-user-select: none;
touch-action: none;
-ms-touch-action: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
<script defer src='main.js'></script>
</head>
<body>
<form id="form">
<canvas style="border: 1px solid black;" id="sign">
</canvas>
</form>
<div id="menu">
<button onclick="createCanvasPngDataUrl()">Create DataUrl</button>
<button onclick="clearCanvas()" id="clear">Clear</button>
</div>
</body>
</html>
Once I upload an image I make 2 clicks over it. That's how (x1,y1) and (x2,y2) are obtained. Given these 4 numbers I waanna draw a rectangle over the image by means for example of P5.js. Then I should say rect(x1,y1,x2,y2) but this never happens. How can I deal with this problem (maybe not by P5)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue Test</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
</head>
<body>
<div id="app">
<button v-on:click="isHidden = false">Load img</button>
<img onclick="showCoords(event)" v-if="!isHidden" v-bind:src="src[z]"></img>
</div>
<script>
var test = new Vue({
el: '#app',
data: {
src: ["cat.jpg", "dog.jpg"],
z: Math.round(Math.random()),
isHidden: true,
}
})
var k=0;
var koors = [];
var flag = false;
function showCoords(event) {
if (k===0){
koors[0] = event.clientX;
koors[1] = event.clientY;
k+=1;
} else if (k===1){
flag = true;
koors[2] = event.clientX;
koors[3] = event.clientY;
}
if ((koors[3] != 0) && (flag)){
console.log(koors)
}
}
//p5
function setup(){
}
function draw(){
console.log(koors[0],koors[1],koors[2],koors[3]);
rect(koors[0],koors[1],koors[2],koors[3])
}
</script>
<script src="p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<script src="js.js"></script>
</body>
</html>
P5 needs a canvas for rendering. If you don't initialize one, it creates it himself (and you are in trouble).
Also, P5 is powerful library, it has tools for events, image processing etc. For current example I wouldn't use any other library (vue).
I created canvas on top of the image (css) and rest is playing with P5.
var test = new Vue({
el: '#app',
data: {
src: [ "https://i.stack.imgur.com/XZ4V5.jpg", "https://i.stack.imgur.com/7bI1Y.jpg"],
z: Math.round(Math.random()),
isHidden: false,
}
})
var recStart;
var coords = {};
/*******************************************************************
* P5 setup
* run once, use for initialisation.
*
* Create a canvas, change dimensions to
* something meaningful(like image dim)
********************************************************************/
function setup(){
var canvas = createCanvas(480, 320);
canvas.parent('app');
}
/*******************************************************************
* P5 draw
* endless loop.
*
* Lets redraw rectangle until second click.
********************************************************************/
function draw(){
if(recStart)
drawRect();
}
/*******************************************************************
* drawRect
*
* Draw a rectangle. mouseX and mouseY are P5 variables
* holding mouse current position.
********************************************************************/
function drawRect(){
clear();
noFill();
stroke('red');
rect(coords.x, coords.y, mouseX-coords.x, mouseY-coords.y);
}
/*******************************************************************
* P5 mouseClicked
*
* P5 event. Again, mouseX and mouseY are used.
********************************************************************/
mouseClicked = function() {
if (mouseButton === LEFT) {
if(!recStart){ // start rectangle, give initial coords
coords.x = mouseX;
coords.y = mouseY;
recStart = true; // draw() starts to draw
} else {
recStart = false; // stop draw()
drawRect(); // draw final rectangle
coords = {}; // clear coords
}
}
};
canvas {
width: 500px;
height:500px;
z-index: 2;
border:1px solid;
position:absolute;
left: 0;
top: 0;
}
img {
z-index: 1;
position: absolute;
border: 2px solid black;
left: 0;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<img id="pilt" v-if="!isHidden" v-bind:src="src[z]"></img>
</div>
It seems that you don't call draw anywhere. You may also consider draw the image into a canvas and than draw rect in this canvas. Checking if koors[3] != 0 is really risky as user may click at 0th pixel.
So I'm trying to do a drag/drop on elements in javascript. The video tutorial I used is here; https://www.youtube.com/watch?v=KTlZ4Hs5h80. I've coded it exactly as it says and I am able to move an object by it's x value but not it's y. So, in summary, whenever I move my mouse the position of the image changes by x, but is constant for y so I can only move my image left and right, and not up and down.
This is my html file:
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<LINK href="gameStyle.css" rel="stylesheet" type="text/css">
</head>
<body>
<section id="main">
<img id="bowl" src="images/bowl.gif">
<img id="egg" src="images/egg.gif">
</section>
<script type="text/javascript" src="gameScript2.js">
</script>
</body>
</html>
This is my javascript file:
function eggIntoBowl()
{
function Draggable(element, dragStart, dragDrop){
this.element = element;
this.dragStart = dragStart;
this.dragDrop = dragDrop;
this.element.classList.add('draggable');
var self = this;
var move = function(event){
event.stopPropagation();
event.preventDefault();
var originalX = parseInt(window.getComputedStyle(this).left);
var originalY = parseInt(window.getComputedStyle(this).top);
var mouseDownX = event.clientX;
var mouseDownY = event.clientY;
function dragEgg(event)
{
self.element.style.left = originalX + event.clientX - mouseDownX + "px"
self.element.style.top = originalY + event.clientY - mouseDownY + "py"
event.stopPropagation();
}
function dropEgg(event)
{
document.removeEventListener('mousemove', dragEgg, true);
document.removeEventListener('mouseup', dropEgg, true);
event.stopPropagation();
}
document.addEventListener('mouseup', dropEgg, true);
document.addEventListener('mousemove', dragEgg, true);
};
this.element.addEventListener('mousedown',move,false);
};
var egg = document.getElementById('egg');
var dragObject = new Draggable(egg);
};
window.addEventListener("load", eggIntoBowl, false);
and this is my css:
body{
width: 896px;
height: 652px;
background: #fff url(images/eggsToBowlScene.jpg) no-repeat;
}
#egg{
position:absolute;
top:190px;
left:56px;
}
#bowl{
position:absolute;
top:141px;
left:231px;
}
.draggable:hover{
cursor: move;
}
Any ideas? I can't work out what I've done wrong. I used another drag/drop tutorial in the past and the same thing happened so I tried this other one, therefore I'm guessing it has something to do with my html file or css..?
In the dragEgg() method you are using "py" instead of "px". This is not meant to be an x and y value, it is short for "pixels". The browser doesn't understand what unit a "py" is so it won't move. Changing it to "px" will tell the browser how many pixels to offset on the Y axis.
self.element.style.top = originalY + event.clientY - mouseDownY + "px";
Why are you using this code if you can use simply the jQuery UI draggable interacion?
http://jqueryui.com/draggable/
I'm making a simple HTML5 app, that will be wrapped to be used on Android, iOS and web browsers. In my app I need a set of points to be dragged and sorted in a certain way, I'm using raphael.js for the animations and movememts and it works fine with 3 or 4 circles, but when I use more the laggy performance appears (mobile browser). I also need the app to be able to draw lines on freehand, like a marker, and the code i'm using refers to drag to, so the performance is awful. The interesting part is that the first moves work great, as i move more elements the performance drops down drastically. It works fine in the pc browser, but works fine for 3 or 4 movements on the mobie browser.
Is there any way to make drag and drop run fast and smooth with large quantity of elements?
Here's the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Raphaël · Drag-n-drop</title>
<link rel="stylesheet" href="demo.css" type="text/css" media="screen">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon-precomposed" href="/Raphael.png">
<link rel="stylesheet" href="demo-print.css" type="text/css" media="print">
<style>
#background {
width: 100%;
height: 100%;
position: fixed;
left: 0px;
top: 0px;
z-index: -1; /* Ensure div tag stays behind content; -999 might work, too. */
}
.stretch {
width:100%;
height:100%;
}
</style>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="raphael-min.js"></script>
<script>
window.onload = function () {
var y = $(window).height();
var x = $(window).width();
y=y/30;
var posX=y;
var posY=y;
var posX2=x-y;
var R = Raphael(0, 0, "100%", "100%");
var nJ=10
var jugador=new Array();
var rival=new Array();
crearJugadores(nJ);
crearRivales(nJ);
function crearJugadores(nJ) {
nJ=nJ;
for (var i=0;i<nJ;i++)
{
jugador[i]= R.circle(posX, posY, y).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
function crearRivales(nJ) {
posX=x-y;
posY=y;
nJ=nJ;
for (var i=0;i<nJ;i++)
{
rival[i]= R.circle(posX, posY, y).attr({fill: "#214dcf", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
var start = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
this.animate({r: (1.5*y), opacity: .3}, 100, ">");
},
move = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
this.animate({r: y, opacity: 1}, 500, ">");
};
R.set(rival).drag(move, start, up);
R.set(jugador).drag(move, start, up);
initDrawing(R);
};
var g_masterPathArray;
var g_masterDrawingBox;
var g_masterPaper;
function initDrawing(R) {
g_masterPaper = R;
var masterBackground = g_masterPaper.rect(0,0,"100%","100%");
masterBackground.attr({fill:"blue", opacity: 0});
masterBackground.mousemove(function (event) {
var evt = event;
var IE = document.all?true:false;
var x, y;
if (IE) {
x = evt.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = evt.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
else {
x = evt.pageX;
y = evt.pageY;
}
// subtract paper coords on page
this.ox = x;
this.oy = y;
});
var start = function () {
g_masterPathArray = new Array();
},
move = function (dx, dy) {
if (g_masterPathArray.length == 0) {
g_masterPathArray[0] = ["M",this.ox,this.oy];
g_masterDrawingBox = g_masterPaper.path(g_masterPathArray);
g_masterDrawingBox.attr({stroke: "#000000","stroke-width": 3});
}
else
g_masterPathArray[g_masterPathArray.length] =
["L",this.ox,this.oy];
g_masterDrawingBox.attr({path: g_masterPathArray});
},
up = function () {
;
};
masterBackground.drag(move, start, up);
masterBackground.toBack();
}
</script>
</head>
<body>
<div id="background">
<img src="cancha.jpg" class="stretch" alt="" />
</div>
<div id="holder"></div>
</body>
</html>
Any ideas??
Thanks
well right now im trying to learn how to use the canvas tag on html, and im having trouble handling mouse events when i apply css to the document.
the issue starts when i move the div containing the canvas and center it on the page, the first poing of the canvas wouldnt be 0 because its centered and for some reason 0,0 would be the beginning of the screen and not the beginning of the canvas, which i found weird because im adding the event listener to the canvas directly.
here is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test</title>
<style type="text/css">
body {
font: 100%/1.4 Verdana, Arial, Helvetica, sans-serif;
background: #42413C;
margin: 0;
padding: 0;
color: #000;
}
#divId {
width: 800px;
height: 600px;
text-align:center;
margin: 20px auto;
background-color:#0099FF;
}
</style>
<script>
window.onload = function () {
var canvas = document.getElementById('canvasId');
var c = canvas.getContext('2d');
alert("lol");
canvas.addEventListener('mousedown', hmd, false);
function hmd(e) {
alert ("x: " + e.clientX + " y: " + e.clientY);
}
}
</script>
</head>
<body>
<div id="divId">
<canvas height="300" width="800" id="canvasId" />
</div>
</body>
</html>
so i read somewhere that the issue was caused by the div, but when i tried to give css directly to the canvas tag it didnt work, so basically what i need to do, is to get that canvas centered or placed anywhere on the screen, but having its first pixel as 0,0.
adding a solution would be hard because its centering automatically, so i would need to know the user resolution to be able to calculate the offset so what im looking for is a way to do it simply with css or something.
To get the coordinates relatively to the canvas, do this:
function hmd(e) {
var rx = e.pageX, ry = e.pageY;
rx -= canvas.offsetLeft;
ry -= canvas.offsetTop;
alert ("x: " + rx + " y: " + ry);
}
This assumes your canvas variable definition is global.
Edit: another method:
function hmd(e) {
var rx, ry;
if(e.offsetX) {
rx = e.offsetX;
ry = e.offsetY;
}
else if(e.layerX) {
rx = e.layerX;
ry = e.layerY;
}
}
Here's what I've been using for my latest experimentation. It works with damn near everything: Borders, paddings, position:fixed elements offsetting the HTML element, etc. It also works on all touch devices and even if the browser is zoomed.
http://jsfiddle.net/simonsarris/te8GQ/5/
var stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingLeft'], 10) || 0;
var stylePaddingTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingTop'], 10) || 0;
var styleBorderLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderLeftWidth'], 10) || 0;
var styleBorderTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderTopWidth'], 10) || 0;
var html = document.body.parentNode;
var htmlTop = html.offsetTop;
var htmlLeft = html.offsetLeft;
function getMouse(e) {
var element = can,
offsetX = 0,
offsetY = 0,
mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
offsetY += stylePaddingTop + styleBorderTop + htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {
x: mx,
y: my
};
}