(JS/CANVAS/HTML) - isPoinToPath inaccurate? - javascript

Below here, the provided snippet for testing purpose.
The yellow(y) represent the canvas area, return "n" on click
The red(r) represent the click area, return "y" on click
The trouble(x) represent the error, return "y" when clicked
How to make it right?
yyyyyyyyyyyyyyy
yyrrrrrrrrrrryy
yyrrrrrrrrrrryy
yyxxxxxxxxxxxyy
yyyyyyyyyyyyyyy
const canvas = document.getElementById('test');
const context = canvas.getContext('2d');
testClicker();
function testClicker() {
const buttonz = new Path2D();
buttonz.rect(canvas.width / 2 - 125, canvas.height / 2 - 70, 250, 80);
context.fillStyle = 'red';
context.fill(buttonz);
var mouseEvent = (event) => {
// Check whether point is inside rect
const isPointInPath = context.isPointInPath(buttonz, event.offsetX, event.offsetY);
let a = isPointInPath ? 'y' : 'n';
alert(a);
}
canvas.addEventListener("click", mouseEvent, false);
}
* {
margin: 0px;
padding: 0px;
}
#test {
position: fixed;
top: 1%;
left: calc(50% - 150px);
width: 300px;
height: 100px;
background: yellow;
}
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="style.css">
<html>
<body>
<canvas id="test"></canvas>
</body>
<script src="main.js"></script>
</html>

You have a mismatch between the CSS setting of height of canvas (100px) and the canvas's attribute height (set to 150px by default).
You are using canvas.height as the basis for setting the path drawing on the canvas.
This snippet makes things match up by setting the height attribute of the canvas to 100.
const canvas = document.getElementById('test');
const context = canvas.getContext('2d');
testClicker();
function testClicker() {
const buttonz = new Path2D();
alert(canvas.height);
buttonz.rect(canvas.width / 2 - 125, canvas.height / 2 - 70, 250, 80);
context.fillStyle = 'red';
context.fill(buttonz);
var mouseEvent = (event) => {
// Check whether point is inside rect
alert(event.offsetY);
const isPointInPath = context.isPointInPath(buttonz, event.offsetX, event.offsetY);
let a = isPointInPath ? 'y' : 'n';
alert(a);
}
canvas.addEventListener("click", mouseEvent, false);
}
* {
margin: 0px;
padding: 0px;
}
#test {
position: fixed;
top: 1%;
left: calc(50% - 150px);
width: 300px;
height: 100px;
background: yellow;
}
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="style.css">
<html>
<body>
<canvas id="test" width="300" height="100"></canvas>
</body>
<script src="main.js"></script>
</html>
See MDN for further explanation of the difference between setting dimensions of the canvas using the width/height attributes and using CSS. If they differ you get scaling/distortion.

Related

How can we do this so that when the screen is clicked, a line is created by a canvas from one vertex to the clicked location?

I have created a circle here so that when the screen is clicked, the circle will move there. And I also have a fixed point (vertex) that I want these two points to be the origin and destination of a line.
const coordinates = document.querySelector(".coordinates");
const circle = document.querySelector(".circle");
const result = document.querySelector(".result");
const numbers = document.querySelectorAll("p");
coordinates.addEventListener("click", e => {
circle.style.setProperty('--x', `${e.clientX}px`);
circle.style.setProperty('--y', `${e.clientY}px`);
})
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(50,100);
ctx.stroke();
canvas {
color: rgb(255, 255, 255);
}
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
position: fixed;
--x: 47px;
left: calc(var(--x) - 10px);
--y: 47px;
top: calc(var(--y) - 10px);
background-color: white;
}
.bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #24232e;
}
.coordinates {
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="bg">
<div class="coordinates">
<canvas id="myCanvas" width="200" height="100" style=""></canvas>
</div>
</div>
<div class="circle">
</div>
</body>
</html>
How to do this with canvas?
! would appreciate <3
You can detect the mouse position on the canvas and draw a line to the coordinates. to get the canvas x and y of the mouse, you have to do some calculations because the site coordinates are a bit different than the canvas ones.
A more detailed description is here: https://stackoverflow.com/a/17130415/14076532
This will work only, if the canvas is big enough, logically...
Hope this helps:
const coordinates = document.querySelector(".coordinates");
const circle = document.querySelector(".circle");
const result = document.querySelector(".result");
const numbers = document.querySelectorAll("p");
coordinates.addEventListener("click", e => {
clicked(e);
circle.style.setProperty('--x', `${e.clientX}px`);
circle.style.setProperty('--y', `${e.clientY}px`);
})
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#de7270"; // change your color here NOTE: this will remain until you change it
ctx.moveTo(0,0);
ctx.lineTo(50,100);
ctx.stroke();
function clicked(event) {
ctx.save(); // some canvas-safety-stuff
ctx.beginPath();
let mousepos = getMousePos(event); // get the mouse position in "canvas-cooridnates"
ctx.clearRect(0,0, c.width, c.height) // erease the canvas
ctx.moveTo(0, 0);
ctx.lineTo(mousepos.x, mousepos.y); // draw the line to the mouse
ctx.closePath();
ctx.stroke(); // closing of the canvas-safety-stuff
ctx.restore();
}
function getMousePos (evt) {
var rect = c.getBoundingClientRect(), // abs. size of element
scaleX = c.width / c.width, // relationship bitmap vs. element for X
scaleY = c.height / rect.height; // relationship bitmap vs. element for Y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
}
}
canvas {
color: rgb(255, 255, 255);
}
.circle {
width: 20px;
height: 20px;
border-radius: 50%;
position: fixed;
--x: 47px;
left: calc(var(--x) - 10px);
--y: 47px;
top: calc(var(--y) - 10px);
background-color: white;
}
.bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #24232e;
}
.coordinates {
height: 100%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="bg">
<div class="coordinates">
<canvas id="myCanvas" width="200" height="100" style=""></canvas>
</div>
</div>
<div class="circle">
</div>
</body>
</html>

How to animate rotateX on scroll in pure JS?

I am trying to create a scroll effect with an image whose rotateX is something like 70deg (or any number).
Whenever someone scrolls the image into viewport, the rotateX of the image has to become 0deg.
In the same way, if someone scrolls the image out of the viewport, the rotateX of the image has to become 70deg again
Here is my code:
let a = 70
function test(){
let image = document.querySelector("img");
let imageTop = image.getBoundingClientRect().top;
let screenpos = window.innerHeight /2
// console.log("test")
if(imageTop < screenpos){
image.style.border = "5px solid green"
// console.log(window.scrollY/10)
image.style.transform = `rotateX(${a=a-2}deg)`
// console.log("its reached ")
}
}
window.addEventListener("scroll",function(){
test()
})
body {
background-color: #ccc;
text-align: center;
margin-top: 100px;
font-family: sans-serif;
}
.bgcolor {
background-color: black;
color: rgba(255, 255, 255, 0.8);
}
div{
perspective:800px;
margin-top:400px;
margin-bottom:200px;
}
div img {
transform:rotateX(66deg);
transition:.9s;
/* border: 1px solid #000; */
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Scroll Please</h1>
<div><img src="https://cdn.pixabay.com/photo/2021/06/10/22/14/stork-6327150__340.jpg" alt="Bird Image"></div>
</body>
</html>
I have created you a small snippet using the example from the Mozilla docs of the Intersection Observer API.
To get a better understanding of everthing going on, feel free to check out the linked docs.
const image = document.querySelector("img");
// Create the Observer on page load
window.addEventListener("load", (event) => {
createObserver();
}, false);
// Setup the Observer
function createObserver() {
let observer;
let options = {
root: null,
rootMargin: "0px",
threshold: buildThresholdList()
};
observer = new IntersectionObserver(handleIntersect, options);
observer.observe(image);
}
// Getting an array with 1000 values between 0.0 and 1.0
function buildThresholdList() {
let thresholds = [];
let numSteps = 1000;
for (let i=1.0; i<=numSteps; i++) {
let ratio = i/numSteps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
// What to do with the observer intersections
function handleIntersect(entries, observer) {
entries.forEach((entry) => {
// Only get values between 0 and 0.5, so that the image only
// ...starts animating when half visible
const maxxedIntersect = entry.intersectionRatio > 0.5
? entry.intersectionRatio - 0.5
: 0;
// Scale the number (0.0 ... 0.5) between 0 and 70
const scaled = scaleBetween(maxxedIntersect, 0, 70, 0, 0.5);
// Get the value that the thing should rotate
// When the element is fully visible, the scaled value will be 70,
// ... so we have to sub from 70 to get 0 in this example
const rotateValue = parseInt(70 - scaled);
// Apply the style
image.style.transform = `rotateX(${rotateValue}deg)`
});
}
// Helper function for scaling numbers between min and max
// Look here: https://stackoverflow.com/a/31687097/9150652
function scaleBetween(unscaledNum, minAllowed, maxAllowed, min, max) {
return (maxAllowed - minAllowed) * (unscaledNum - min) / (max - min) + minAllowed;
}
body {
background-color: #ccc;
text-align: center;
margin-top: 100px;
font-family: sans-serif;
}
.bgcolor {
background-color: black;
color: rgba(255, 255, 255, 0.8);
}
div > img{
margin-top: 400px;
margin-bottom: 600px;
perspective: 800px;
border: 5px solid green;
transition: .1s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Scroll Please</h1>
<div>
<img src="https://cdn.pixabay.com/photo/2021/06/10/22/14/stork-6327150__340.jpg"
alt="Bird Image">
</div>
</body>
</html>

create a curved sidebar for user dashboard background

I would like to create a curved side bar for my dashboard panel. I've tried 2 ways:
create a svg and path: that result was not good at all.
create with js: the result was good but it was rasterized :|
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Quadratic Bézier curve
ctx.beginPath();
ctx.moveTo(280, 0);
ctx.quadraticCurveTo(240, 90, 270, 150);
ctx.lineTo(320, 320);
ctx.lineTo(320, 0);
ctx.fillStyle = "#0984e3";
ctx.fill();
//
const hes = document.getElementById('hesam');
const ctxx = canvas.getContext('2d');
// Quadratic Bézier curve
ctxx.beginPath();
ctxx.moveTo(281, 0);
ctxx.quadraticCurveTo(240, 90, 280, 150);
ctxx.lineTo(320, 320);
ctxx.lineTo(320, 0);
ctxx.fillStyle = "#74b9ff";
ctxx.fill();
#canvas {
width: 100%;
height: 100%;
position: absolute;
float: right;
}
#hesam {
width: 100%;
height: 100%;
position: absolute;
float: right;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=">
<title></title>
</head>
<body>
<canvas id="canvas"></canvas>
<canvas id="hesam"></canvas>
</body>
</html>
https://codepen.io/hessamr/pen/vYLzePX
How can I have this result with vectorized and have quality to use bg of a side bar.

How to implement resizable div with fixed increments in Javascript?

I want to implement a vertical resizable div such that it increases height in certain fixed intervals. I don't want to use any libraries and looking for plain JS implementation. Here is jquery version: https://jqueryui.com/resizable/#snap-to-grid
This code works good but increases height by one pixel on each mousemove (vertically).
When I try to increase height by 10, the height increases but the mouse pointer does not stick to the base of div..,
https://plnkr.co/edit/3VesixHE2B7N46f8N7Bg?p=preview
const divElement = document.querySelector('.ns-resize');
const element = document.querySelector('.resizable');
let original_height = parseFloat(getComputedStyle(element, null).getPropertyValue('height').replace('px', ''));
let original_Y = element.getBoundingClientRect().top;
divElement.onmousedown = function(mouseDownEvent) {
mouseDownEvent.preventDefault();
var original_mouse_y = mouseDownEvent.pageY;
document.addEventListener('mousemove', resize);
document.addEventListener('mouseup', stopResize);
function resize(mouseUpEvent) {
//cmp.increment = cmp.increment + 15;
const height = original_height + (mouseUpEvent.pageY - original_mouse_y);
if (height > 15 && height < 900) {
mouseUpEvent.pageY = mouseUpEvent.pageY ;
element.style.height = height + 'px';
divElement.innerHTML = element.style.height;
}
}
function stopResize() {
document.removeEventListener('mousemove', resize)
}
}
/* Styles go here */
.resizable {
width: 100px;
height : 100px;
border:1px solid red;
position: absolute;
}
.container {
position : relative;
}
.ns-resize {
position: absolute;
bottom: 0px;
cursor: ns-resize;
width: 100%;
}
<!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>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="resizable">
<div class="ns-resize">
<span> </span>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
}
I could increase height by one pixel on every mousemove event, but what I really want is to increase by 10px each time.
As indicated in my comment, CSS already has a resize property you can use to make an element resizable. The only thing you need to do after a resize, is round the current height to the nearest 10px.
document.querySelector( '.resizable' ).addEventListener( 'mouseup', event => {
const current_height = parseInt( event.target.style.height, 10 );
event.target.style.height = Math.round( current_height / 10 ) * 10 + 'px';
console.log( `changed height from ${ current_height }px to ${ event.target.style.height }` );
});
.resizable {
border: 1px solid red;
height: 100px;
overflow: hidden;
resize: vertical;
width: 100px;
}
<div class="resizable"></div>
Only mighty want to add a check now to not run the function when something else inside the div is clicked.

why can't log keycode value to the console window?

Hey guy's I'm trying to make a snake game in JS. Right now I'm making the function that will determine the direction of the snake, but at the moment I just want to log the keycode of any given key to the console, but it comes up as undefined? Why is this? I have the keycode stored into a variable before I log it? thanks for the help:)
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 750;
canvas.height = 500;
//create stroke
ctx.strokeStyle = 'limegreen';
ctx.strokeRect(375, 250, 15, 15);
//create square
ctx.fillStyle = 'limegreen';
ctx.fillRect(375, 250, 15, 15);
//read user's direction
document.addEventListener('keydown', changeDirection);
function changeDirection(e) {
let code = e.keycode;
console.log(code);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Snake Game</title>
<style>
body {
background-color: #333;
}
canvas {
background-color: #4d4d4d;
margin: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 750px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="script.js"></script>
</body>
</html>
Try e.keyCode instead of e.keycode

Categories

Resources