I'm making an Etch-a-Sketch project and I want my grid to be filled with color on mouseover only if mousedown is true. My code seems to work, but if I keep drawing, it bugs and starts drawing even after mouseup. I can't figure out where the problem is in my code:
HTML:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<style media="screen">
</style>
</head>
<body>
<div id='cont' style="height: 600px; width: 600px; display: flex; flex-wrap: wrap;">
</div>
<script src="script.js">
</script>
</body>
</html>
JS:
const container = document.getElementById('cont');
const contSize = 600; //size of container in pixels
let size = 16; //number of columns and rows
let mouseDown = false;
generateGrid();
function generateGrid() {
for (i = 0; i < (size * size); i++) {
const createDiv = document.createElement('div');
createDiv.style.width = contSize / size + 'px';
createDiv.style.height = contSize / size + 'px';
createDiv.className = 'cell';
container.appendChild(createDiv);
}
}
document.addEventListener('mouseover', function(e) {
if (mouseDown) {
if (e.target.className === 'cell') {
e.target.style.backgroundColor = 'orange';
}
}
})
window.addEventListener('mousedown', () => {
mouseDown = true;
})
window.addEventListener('mouseup', () => {
mouseDown = false;
})
You probably need more events to set "mouseDown" to false.
Consider what happens if the user clicks and holds, moves the mouse outside, then releases. The mouseup won't be called, and "mouseDown" will be true even though the mouse is released.
Maybe this will help?
window.addEventListener("mouseout", () => {
mouseDown = false;
}
Found the problem - I just needed to add style 'user-select:none' to my page or container to avoid selecting and dragging the content.
I've got an issue with the element position properties, in particular the 'left' property. I've created a grey block shape in css and rotated it by 0.17rad in js. I want to move the block diagonally across the screen so that it moves a distance of 3px for every 20 milliseconds. If you use your good old SOHCAHTOA and pythagoras laws, that comes out to 0.5075470472px in the left direction and 2.956754301px in the upwards direction every 20ms.
html:
<html lang='en'>
<head>
<meta charset="UTF-8">
<link rel='stylesheet' href='.css'>
</head>
<body>
<div id='block'></div>
<script src='.js'></script>
</body>
</html>
css:
#block {
width: 19px;
height: 31px;
position: absolute;
background-color: grey;
}
js:
var block = document.getElementById('block');
block.style.left = '0px';
block.style.top = '500px';
block.style.transform = 'rotate(0.17rad)';
setInterval(function() {
block.style.left = (parseInt(block.style.left) + 0.5075470472) + 'px';
block.style.top = (parseInt(block.style.top) - 2.956754301) + 'px';
}, 20);
What happens in my case is the block moves correctly in the upward direction but doesn't move at all in the left direction. Any thoughts?
parseInt is rounding the numbers, what you need is to use parseFloat:
block.style.left = (parseFloat(block.style.left) + 0.5075470472) + 'px';
block.style.top = (parseFloat(block.style.top) - 2.956754301) + 'px';
I know how to move a div element using top/left position increments. But I heard that translate3d gives performance improvements, and so I wanted to check it out.
Lets say I have this,
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.position = 'absolute';
document.body.appendChild(div);
The following,
div.getBoundingClientRect().left
gives the value 8.
Now, calling
div.style.transform = 'translate3d(10px,0,0)'
moves the element to the right by 10px as expected as seen by
div.getBoundingClientRect().left
giving the value 18.
But repeatedly executing,
div.style.transform = 'translate3d(10px, 0, 0)';
does not move the div to the right repeatedly. Instead I have to increment the first argument of translate3d to higher values (eg. 20, 30 etc) to move it repeatedly.
This makes me think the translation is calculated from some initial point. But googling around, I could not find how to update this initial point, so that translate3d(10px, 0, 0) works in a loop.
I tried updating the div.style.left property, but it still does not work.
So can someone tell me how translate3d calculates the translation? And if there is a way to use translate3d(10px,0,0) and some origin resetting, to make a div move repeatedly?
(The end goal is to make a div move to the right every time it is clicked, using translate3d)
When you are doing div.style.transform = 'translate3d(10px, 0, 0)'; you are just removing the transform value to replace it by another, so your element will keep the same position. If you want to move your element using translate3d, you can use a variable and increment it every click :
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '100px';
div.style.background = 'red';
div.style.position = 'absolute';
document.body.appendChild(div);
var leftValue = 0;
var increment = 10;
var button = document.querySelector('button');
button.addEventListener('click', function(event) {
leftValue += increment;
div.style.transform = 'translate3d('+leftValue+'px,0,0)';
})
<button>Move</button>
For multiple elements, using getBoundingClientRect().left
When calculating a new offset, we have to take into account the initial position of the element or the new value will be wrong. The problem can be see here.
To avoid this, we can store the initial position of the element and then substract this value when calculating the new offset:
var increment = 10;
var moveBoxes = document.getElementsByClassName('moveBox');
Array.from(moveBoxes).forEach(function(box) {
var initialOffset = getComputedStyle(box).getPropertyValue('left').replace('px', '');
box.addEventListener('click', function(event) {
var offset = this.getBoundingClientRect().left - initialOffset + increment;
this.style.transform = 'translate3d('+offset+'px,0,0)';
});
});
.moveBox {
width: 100px;
height: 100px;
background: red;
position: absolute;
}
<div class="moveBox" style="left: 32px;"></div>
<div class="moveBox" style="top: 120px; left: 100px;"></div>
Using a forEach loop instead of a classical for loop let us store the right initialOffset value in each listeners (there are some others ways to achieve this). Since the array of div is a HTML collection, using Array.from is required to use forEach.
translate3d(10px,0,0)
Is defined here: https://www.w3.org/TR/css-transforms-1/#funcdef-translate3d
I wrote a CodePen to see your issue: https://codepen.io/cyruscuenca/pen/mamjgw?&editable=true
I also scanned the doc, and it seems like the position is based on a coordinate system, and there seems to be separate origin properties. I would read those sections.
The sections that I found that look to be related are 6 and 3.
Hope this helps!
It's very simple.
For the point of the count this function is used your current coordinates by X, Y and Z axes.
So, if you want to move your block, you should always increment this valuse(these values) of the axes.
You can apply multiple transformations on the same element.
div.style.transform = 'translate3d(10px,0,0) translate3d(10px,0,0) translate3d(10px,0,0)';
Which would mean you need to append the string on every loop iteration:
div.style.transform += ' translate3d(10px,0,0)';
However, if you have too many transformations, the string would become very long and might impact the performance, let alone the readability.
If it's always the same transformation you're applying, why not increase the 10px along the way while iterating through the loop:
var offset = 10;
// then on every iteration
div.style.transform = 'translate3d(' + offset + 'px,0,0)';
offset += 10;
Taking ideas from #Arkellys answer (the accepted one), I came up with a solution which seems to be working fine for me. I am a JS newbie so I do not know how well it will hold up. Anyways here it is in case it helps anyone,
// Create container
var container = document.createElement('div');
container.style.width = '1000px';
container.style.height = '500px';
container.style.border = '2px solid black';
container.style.background = 'lightblue';
container.style.margin = '0';
container.style.padding = '10px';
document.body.appendChild(container);
var containerPosition = container.getBoundingClientRect();
// 'click' Callback function generator.
// I pass the initial position to the generator, who then generates a callback
// function which holds this value for use when the event occurs.
function clickCallbackGenerator(initialPos, increment){
var left = initialPos.left;
var clickCallback = function(event) {
var newLeftPosition = this.getBoundingClientRect().left - left + increment;
this.style.transform = `translate3d(${newLeftPosition}px, 0, 0)`;
console.log('clicked : ', this.innerHTML,' now at : ', this.getBoundingClientRect().left);
};
return clickCallback;
}
// function to create 'move-on-click' div nodes
function createNodeDiv(position, text) {
var div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = `${position.top}px`;
div.style.left = `${position.left}px`;
div.style.border = '2px solid blue';
div.style.background = 'black';
div.style.color = 'white';
div.style.margin = '0';
div.style.padding = '0';
div.style.cursor = 'pointer';
div.innerHTML = text;
div.setAttribute('class', 'node');
div.setAttribute('contenteditable', 'true');
container.appendChild(div);
div.addEventListener('click', clickCallbackGenerator(div.getBoundingClientRect(), 10));
console.log('Created : ', div.innerHTML, ' at : ', div.getBoundingClientRect().left);
return div;
}
var defaultPosition = {x: containerPosition.left, y: containerPosition.top};
var increment = 10;
var nodes = [];
nodes.push(createNodeDiv({left: containerPosition.left, top: containerPosition.top}, 'hello'));
nodes.push(createNodeDiv({left: containerPosition.left+50, top: containerPosition.top+50}, 'world'));
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="description" content="Free Web tutorials">
<meta name="keywords" content="HTML,CSS,XML,JavaScript">
<meta name="author" content="John Doe">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script src="script.js"></script>
</body>
</html>
I used a function clickCallbackGenerator to generate the callbacks for each moveable div. That is the only thing I changed.
So the idea is - I want to get the canvas position style to be fixed through js, so I don't get the scroll bars.
The thing is - I can change the style easily with chrome inspector and all works fine, but js refuses to corporate...
function setup() {
//full screen setup
canvas = createCanvas(window.innerWidth*2,window.innerHeight*2);
canStyle = canvas.style;
canvas.style.position = "fixed";
mainWrap = document.getElementById('mainWrap');
canvas.parent(mainWrap);
This is what I get instead :
The html, body and main wrap are 100% , just the way I want it, but the canvas itself is stretched, but not fixed...
I really don't know what I'm doing wrong... Ideas?
The manual chrome inspector edit does the job...
Whole Code
HTML:
<html>
<head>
<meta charset="utf-8">
<title>Sky</title>
<link href="style.css" rel="stylesheet" type="text/css"/>
<script language="javascript" type="text/javascript" src="libs/p5.js"></script>
<script language="javascript" src="libs/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<script language="javascript" type="text/javascript" src="star.js"></script>
<style> body {padding: 0; margin: 0;} </style>
</head>
<body>
<div id="mainWrap">
</div>
</body>
</html>
css:
html, body, #mainWrap {
height:100%;
width:100%;
margin:0px;
}
body{
background-color: #222222;
}
JS:
var mainWrap;
var sky = [];
var x;
var y;
var trans = false;
function setup() {
//full screen setup
canvas = createCanvas(window.innerWidth*2,window.innerHeight*2);
canStyle = canvas.style;
canvas.style.position = "fixed";
mainWrap = document.getElementById('mainWrap');
canvas.parent(mainWrap);
for(var i = 0; i < 1; i++){
var star = new Star(i, random(width),random(height), Math.floor(random(1,4)));
sky[i] = star;
console.log(sky[i]);
}
}
function draw() {
background(34,34,34);
x = mouseX;
y = mouseY;
if(trans === false){
translate(x-(width/2),y-(height/2));
}
for (var i=0; i < sky.length; i++){
sky[i].show();
sky[0].fall(0.4,0.3);
}
}
Star obj:
function Star(id,xCord, yCord, parallax) {
this.parrlax = parallax;
this.id = id;
this.x = xCord;
this.y = yCord;
this.r = parallax;
noStroke();
this.show = function(){
fill(255,255,255, random(30*this.parrlax,this.parrlax*40));
ellipse(this.x, this.y, this.r*2, this.r*2);
}
this.fall = function(xMove, yMove) {
this.x += xMove;
this.y += yMove;
fill(100,100,100);
ellipse(this.x,this.y,3,3);
}
}
Assuming createCanvas is a method form P5.js, you need to access the underlying DOM element of the created canvas:
canvas = createCanvas(window.innerWidth*2,window.innerHeight*2);
// canvas here refers to an instance of P5 canvas, not a HTML5 canvas element,
// but the real DOM canvas is available as either .canvas or .elt
canvas.elt.style.position = "fixed";
This is what i have so far, it makes my red circle appear and then when clicked it moves from the top left of the screen to the coodinates x, y(300, 800)
<!DOCTYPE html>
<html>
<head>
<style>
body
{
background-color:#000080;
}
h1
{
</style>
<title>Mouse click game</title>
<h1 style="text-align:center;color:white;font-family:verdana;font-size:50px;">Left click on the dots!</h1>
</br>
</br>
<script type="text/javascript">
function red_circleClick()
{
var red_circle = document.getElementById('red_circle');
red_circle.hidden = true;
red_circle.style.top = 300 + "px";
red_circle.style.left = 800 + "px";
red_circle.hidden = false;
}
</script>
</head>
<body>
<img src="/Users/lorraine/Desktop/MOUSE/red_circle.png" id="red_circle" onclick="red_circleClick();" style="position:absolute; left: 400; top: 100; width: 200; height: 200;"/>
</body>
</html>
What i need it to do is move to a random spot on the screen and do that 10 times.
So I need it to appear, user clicks on it. When they click it jumps to another spot onscreen. when they click it again in its new location it jumps to an new spot onscreen, and repeat a certain amount of times(10)
Is it possible that the circle could appear in a location outside the current screen? Like x,y(1000, 1000)
Found this code, just not 100% on how/where to insert it.
<script type="text/javascript">
function changeImg()
{
var x = Math.floor(Math.random()*300);
var y = Math.floor(Math.random()*300);
var obj = document.getElementById("emotion");
obj.style.top = x + "px";
obj.style.left = y + "px";
obj.onclick= "changeImg();"
}
New enough to Javascript and html!
Thanks very much for the help in advance!
This function gets run whenever you click the dot
function red_circleClick()
{
var red_circle = document.getElementById('red_circle');
red_circle.hidden = true;
red_circle.style.top = 300 + "px";
red_circle.style.left = 800 + "px";
red_circle.hidden = false;
}
All you have to do is randomize your numbers
red_circle.style.top = 300 + "px";
red_circle.style.left = 800 + "px";
Open up a console in chrome or what have you and run Math.random() Then try Math.floor(.1433) Then maybe Math.floor(.019231*100) See what you can get. Replace 300 and 800 with whatever you come up with.
As for making it stop at 10 times, just use an if statement and a counter.