I have a div#panel which I use to print information about parent elements relative to the element which I clicked on. This means that the div element does not have fixed width and height.
I needed to calculate position for the element div#panel which is positioned using the CSS styles left and top. My goal is to keep the div#panel on the screen, it should not go outside of the current view/screen.
My calculation looks like this:
var ClientW = jQuery(window).width();
var ClientH = jQuery(window).height();
var w = $('div#panel').width();
var h = $('div#panel').height();
var offsetY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
var offsetX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
var y, x;
if ( e.clientY > ClientH - h )
y = offsetY + ClientH - (e.clientY-ClientH);
else
if ( e.clientY < 0 + h )
y = offsetY + e.clientY + (h-e.clientY);
else
y = e.clientY < ClientH/2 ? offsetY + e.clientY - h/2 : offsetY + ( e.clientY+h/2 > ClientH-h ? ClientH-h : e.clientY+h/2 ) ;
x = (e.clientX > ClientW - w/2 )?offsetX + ClientW-w : offsetX + e.clientX;
$('#panel').css({ left: x, top: y })
It works almost perfectly, but near the bottom of the client area, just above the bottom scrollbar (20-40px), the element does not fit on the screen. When I click too close to the bottom scrollbar so it will disappear bellow the scrollbar. How could I correct or improve the calculation for the y position?
PS: I do not need to correct x at the moment because the calculation should be similar to y ... later.
Finally I have found that the problem was in the first condition, not in the last.
if ( e.clientY > ClientH - h)
y = offsetY + e.clientY - h;
else
if ( e.clientY < 0 + h )
y = offsetY + e.clientY + (h-e.clientY);
else
y = e.clientY < ClientH/2 ? offsetY + e.clientY - h/2 : offsetY + ( e.clientY > ClientH-h? ClientH-h : e.clientY+h/2 ) ;
It should be universal solution. Very useful when you need your box fit to the current view.
Related
I have made a circle that follows the cursor using jquery which works fine but i want to give it a smoother effect, i have tried using timeout but that wont work which is kinda obvious so is there any other way to achieve this ?
Also whenever the cursor is close to the border of the webpage or crosses it the circle also goes outside the webpage creating a scrollbar can this be avoided by any way ?
My code -
var mouseX = 0, mouseY = 0;
var xp = 0, yp = 0;
let mouseMovementStoppedTimer;
const mouseMovementStopped = function() {
$("#circlecc").css({ opacity: 0});
}
$(document).mousemove(function(e){
$("#circlecc").css({opacity: 1})
mouseX = e.clientX - 12;
mouseY = e.clientY - 12;
setTimeout(() => {
$("#circlecc").css({left: mouseX +'px', top: mouseY +'px'});
}, 50)
clearTimeout(mouseMovementStoppedTimer);
mouseMovementStoppedTimer = setTimeout(mouseMovementStopped, 120);
});
My Website
Yes, you can avoid it, by detecting whether it would be outside the edge and making corrections:
let radius = 5; //you can have your own value here
function getX(x) {
if (x - radius < 0) return radius;
if (x + radius >= $(window).width()) return $(window).width() - radius - 1;
return x;
}
function getY(y) {
if (y - radius < 0) return radius;
if (y + radius >= $(window).height()) return $(window).height() - radius - 1;
return y;
}
$(document).mousemove(function(e){
$("#circlecc").css({opacity: 1})
mouseX = e.clientX - 12;
mouseY = e.clientY - 12;
setTimeout(() => {
$("#circlecc").css({left: getX(mouseX) +'px', top: getY(mousey) +'px'});
}, 50)
clearTimeout(mouseMovementStoppedTimer);
mouseMovementStoppedTimer = setTimeout(mouseMovementStopped, 120);
});
What I want:
I have a div and I want to move it around the canvas but limit it to canvas width and height
What I have:
I'm using p5.dom.js library
P5js code:
let dragging = false;
let offsetX, offsetY, onsetX, onsetY;
let canvasWidth, canvasHeight;
let currentDragDiv;
function setup() {
canvasWidth = windowWidth < 400 ? 400 : windowWidth;
canvasHeight = windowHeight < 400 ? 400 : windowHeight;
canvas = createCanvas(canvasWidth, canvasHeight)
.mousePressed(createDiv);
}
function draw() {
background(200);
if(dragging){
if(mouseX + onsetX < canvasWidth && mouseX + offsetX > 0){
currentDragDiv.position(mouseX + offsetX, currentDragDiv.y);
}
if(mouseY + onsetY < canvasHeight && mouseY + offsetY > 0 ){
currentDragDiv.position(currentDragDiv.x, mouseY + offsetY);
}
}
}
function createDiv(){
let div = createDiv("")
.mousePressed(function(){ dragDiv(div); })
.mouseReleased(function(){ dropDiv(div); })
.position(mouseX, mouseY);
}
function dropDiv(){
dragging = false;
currentDragDiv = null;
}
function dragDiv(d){
currentDragDiv = d;
dragging = true;
offsetX = currentDragDiv.x - mouseX;
offsetY = currentDragDiv.y - mouseY;
onsetX = currentDragDiv.width + offsetX;
onsetY = currentDragDiv.height + offsetY;
}
The Problem:
This code is working great but if the user moves the mouse too quickly, the div doesn't go until the border of the canvas things like this happens (I dragged and moved the div very fast to the right and it stoped in the middle of screen). This problem makes the variable onsetX and onsetY goes wrong and mess up a lit bit deppending on how much the div is away from the canvas border.
Is it possible to remove this "error" and make the div go until the border of canvas?
Observations:
I removed some of the code that I think it's not necessary for this question.
The variables onsetX and onsetY are the oposite of offsetX and offsetY, it's the position of the border from the mouse position, but because english isn't my native language, I didn't know how to name the variable. Recommendations would be good.
In your current code the dragging is completely omitted, if the border of the canvas is exceeded:
if(mouseX + onsetX < canvasWidth && mouseX + offsetX > 0){
currentDragDiv.position(mouseX + offsetX, currentDragDiv.y);
}
if (mouseY + onsetY < canvasHeight && mouseY + offsetY > 0 ){
currentDragDiv.position(currentDragDiv.x, mouseY + offsetY);
}
Instead of that you have to limit the dragging to the range from 0 to canvasWidth respectively 0 to canvasHeight. This means you have to "clamp" the dragging to this range:
function draw() {
let newX, newY;
background(200);
if(dragging){
newX = mouseX + offsetX;
if ( newX > canvasWidth ) {
newX = canvasWidth - currentPostIt.width;
}
if ( newX < 0 ) {
newX = 0;
}
newY = mouseY + offsetY;
if ( newY > canvasHeight ) {
newY = canvasHeight - currentPostIt.height;
}
if ( newY < 0 ) {
newY = 0;
}
currentDragDiv.position(newX, newY);
}
}
I am having some problems involving full screening in video elements:
I have a code which tracks X and Y cords as mouse moves over video elem:
<video id="video" preload=auto autoplay controls>
<source src = "http://upload.wikimedia.org/wikipedia/commons/7/79/Big_Buck_Bunny_small.ogv">
</video>
function getElementCSSSize(el) {
var cs = getComputedStyle(el);
var w = parseInt(cs.getPropertyValue("width"), 10);
var h = parseInt(cs.getPropertyValue("height"), 10);
return {width: w, height: h}
}
function mouseHandler(event) {
var size = getElementCSSSize(this);
var scaleX = this.videoWidth / size.width;
var scaleY = this.videoHeight / size.height;
var rect = this.getBoundingClientRect(); // absolute position of element
var x = ((event.clientX - rect.left) * scaleX + 0.5)|0; // round to integer
var y = ((event.clientY - rect.top ) * scaleY + 0.5)|0;
console.log("x " + x);
console.log("y " + y);
}
video.addEventListener("mousemove", mouseHandler);
Now, it works perfectly well when the video is viewed on normal mode;
if for example the video is 237x132,
then max left is 0x, and max top is 0y.
The problem occurs in full mode;
there are black borders on top and bottom as you can see:
https://i.imgsafe.org/452a426.jpg
now, this is true to every video I checked.
So in my script above, for some reason it counts the
black borders as part of the video; the x is ok, but
the y is not; the y starts at the top corner of
the video, upon the black border.
I need to be very precice here, and to completely ignore somehow the black borders - the y should start at the real pixel and end at the real pixel.
So, every type of movie that is played in full mode should is supposed to ignore the black borders.
Thank you so much for your time.
function mouseHandler(event) {
var rect = this.getBoundingClientRect();
if (!('height' in rect)) {//for IE8
rect.height = rect.bottom - rect.top;
rect.width = rect.right - rect.left;
}
var actualVideoHeight = rect.height;
var actualVideoWidth = rect.width;
var borderTop = 0;
var borderLeft = 0;
var onBottomBorder = false;
var onRightBorder = false;
var videoRatio = this.videoWidth / this.videoHeight;
var elementRatio = rect.width / rect.height;
if (videoRatio > elementRatio) {//video is wider than element
actualVideoHeight = this.videoHeight * rect.width / this.videoWidth;//actual height of video without borders
borderTop = (rect.height - actualVideoHeight) / 2;//calculate size of top border
if (event.clientY > actualVideoHeight + borderTop) {//check if mouse in on bottom border
onBottomBorder = true;
}
} else if (videoRatio < elementRatio) {//element is wider than video
actualVideoWidth = this.videoWidth * rect.height / this.videoHeight;//actual width of video without borders
borderLeft = (rect.width - actualVideoWidth) / 2;//calculate size of left border
if (event.clientX > Math.round(actualVideoWidth + borderLeft)) {//check if mouse in on right border
//onRightBorder = true;
}
}
var x = Math.round((event.clientX - rect.left - borderLeft) * (this.videoWidth / actualVideoWidth)); //scale and round to integer
var y = Math.round((event.clientY - rect.top - borderTop) * this.videoHeight / actualVideoHeight);
/*
x will be negative if mouse is on left border
y will be negative if mouse is on top border
onRightBorder will be true if mouse is on right border
onBottomBorder will be true if mouse is on bottom border
*/
if (y > 0 && x > 0 && !onRightBorder && !onBottomBorder) {
console.log('x ' + x);
console.log('y ' + y);
}
}
I'm creating a website with a rotating wheel. The user should be able to rotate this wheel with dragging it with mouse. I implemented this in jQuery and it works(rotates). But it behaves as expected just between 90 degrees and 180 degrees. When it rotates more or less than this range, I see some unexpected bounces.
This is my code:
$(document).ready(function(){
var isDragging = false;
$("#box").mousemove(function(e){
if(isDragging){
e.preventDefault();
var rx = $(this).width() / 2;
var ry = $(this).height() / 2;
var px = e.clientX - $(this).offset().left - rx;
var py = e.clientY - $(this).offset().top - ry;
var a = Math.atan2(py,px) * 180 / Math.PI + 90;
if(py <= 0 && px < 0){a = 360 + a;}
$(this).css("-webkit-transform","rotate(" + a + "deg)");
}
});
$("#box").mousedown(function(){
isDragging = true;
});
$("*").mouseup(function(){
isDragging = false;
});
});
What is the problem? How to solve it?
You should check out the answer posted here.
How to make object rotate with drag, how to get a rotate point around the origin use sin or cos?
Here is the working fiddle from their answer
http://jsfiddle.net/mgibsonbr/tBgLh/11/
it involves making your html look similar to this.
<div class="draggable_wp">
<div class="el"></div>
<div class="handle"></div>
</div>
Within your if(isDragging) clause:
var element = document.getElementById("rotatable");
var mouseX = e.pageX || e.clientX + document.documentElement.scrollLeft;
var mouseY = e.pageY || e.clientY + document.documentElement.scrollTop;
var rect = element.getBoundingClientRect();
var s_rad = Math.atan2(
mouseY - rect.top - rect.height / 2,
mouseX - rect.left - rect.width / 2
);
var degree = Math.round(90 + (s_rad * (180 / (Math.PI))) / 15) * 15;
element.style.transform = 'rotate(' + degree + 'deg)';
I want to create a drag and scroll effect:
-> mouse down
-> drag and mouse move
-> the window will scroll according to the amount of mouse move
-> mouse up
-> scroll stops
Now, the problem I have is when I drag and move, the window DOM elements will shake.
I added a offset check, it mitigates the shaking problem, however not solved.
Can anyone help me?
below is the main code and the full working jsFiddle is at: http://jsfiddle.net/mifeng/sGvA4/1/
container.mousedown(function(e) {
mouseX = e.pageX;
mouseY = e.pageY;
console.log("CON: " + conX + "," + conY);
console.log("DOWN: " + mouseX + "," + mouseY);
container.mousemove(function(e) {
//console.log("INNER-DOWN: " + mouseX + "," + mouseY);
offsetX = e.pageX - mouseX;
offsetY = e.pageY - mouseY;
// offset check
if (offsetX > 10 || offsetX < -10 || offsetY > 10 || offsetY < -10) {
conX -= offsetX;
conY -= offsetY;
window.scrollTo(conX, conY); // scrollTo
mouseX = e.pageX;
mouseY = e.pageY;
}
});
});
Here are 2 plugins that do what you're after.
http://archive.plugins.jquery.com/project/Dragscrollable
http://azoff.github.io/overscroll/