How to subtract pixels from an elements current position using only JavaScript? - javascript

Without using jQuery, is there a way to get an element's current position and add/subtract from it? Let's say an element has this CSS
position: relative;
top: 400px;
/*400px away from the top*/
Can JavaScript get the amount of pixels from "top" and subtract from it? I know that I can directly edit the top property with document.getElementById("element").style.top , but I want to get the value itself first, then subtract a number of pixels from that value, and then put the new value as the position. Is this possible?

Yes you need to get the computedStyle of the element let rect = getComputedStyle('el'), assign this to a variable then you can use the top position to get amount set in your class => rect.top will give you the top position.
const cont = document.querySelector('.cont')
function getTopPos(el){
// get the computed style of element
// get the top position using .top
// split at px and get the first index which will be the number
// subtract it by desired amount and concatenate px measurement back to the value
let was = getComputedStyle(el).top;
el.style.top = `${getComputedStyle(el).top.split('px')[0] - 300}px`
console.log(`top position is now: ${getComputedStyle(el).top.split('px')[0]}px, was: ${was}`)
}
getTopPos(cont)
* {
margin: 0;
padding: 0;
}
.cont {
width: 100px;
height: 100px;
background: red;
position: relative;
top: 400px;
}
<div class="cont">Was 400 pixels from top, now 100 pixels from top</div>

Something like this? Get the position from the top of the viewport, then subtract a value and return the new "offset from top value":
const offsetValue = 49
const findNewPosition = (offset) => {
const element = document.querySelector('#elementId').getBoundingClientRect().top
return element - offset
}
findNewPosition(offsetValue)

I think this works (it did for my case):
var eee = document.getElementById('elementId').style.top.replace("px", "");
var aaa = parseInt(eee, 10);
aaa = aaa - 300;
document.getElementById('elementId').style.top = aaa + `px`;

Related

Getting the X,Y coordinates or POSITION of a slider-handle? [duplicate]

Is there any way to get the pixel position of the slider handle of an HTML5 range input ?
<input type="range" id="combicalc_contribution-slider" min="1" max="50" value="25">
I have tried calculating the position using a combination of max, min & value to work out the percentage 'down the track' but the calcualted value varies to the left at lower values and the right at higher values.
Here's the code for that:
var sliderWidth = slider[0]['clientWidth'];
var sliderPos = slider[0]['valueAsNumber'] / slider[0]['max'];
jQuery(id).closest('.sliderContainer').append('<div class="sTt">' + val + '</div>');
var sTtWidth = jQuery(id).closest('.sliderContainer').find('.sTt').outerWidth(true) / 2;
var ttPos = (sliderWidth * sliderPos);
ttPos = ttPos - sTtWidth;
ttPos = ttPos + 'px';
jQuery('.sTt').css({'left': ttPos});
The overall aim is to place a 'tooltip' above the slider handle as it moves with the value in it.
Here's a jsFiddle which highlights the issue
Try this
val = slider.val();
// Measure width of slider element. adjust by 15 to account for padding/border
width = slider.width() - 15;
// Calculate percentage between left and right of input
min = slider.attr('min');
max = slider.attr('max');
percent = (val - min) / (max - min);
// Janky value to get pointer to line up better
offset = -3;
// the position of the output
newPosition = width * percent + offset;
slider.next('output')
.css({left: newPosition})
.text(val);
Adapted from here
I ran into this same problem, where the label position was skewed at the far ends of the slider:
I noticed that the problem incrementally improved as you move towards the center of the slider and then incrementally got worse as you moved toward the other end:
I think what is happening is that because the thumb must not extend beyond the bounds of the slider track, half of the thumb's width is incrementally shaved from the thumb's position as it moves down the slider. The end result is that when the thumb's edge (not its center) reaches the end of the slider, the slider value is at its min or max.
So, to fix the skewed label, we need to calculate that dynamic offset. Here is an extra verbose offset calculation in an attempt to better explain the problem (and solution):
var half_thumb_width = 25/2;
var half_label_width = $(range_input).prev('span.rs-label').outerWidth()/2;
var slider_width = $(range_input).width();
var center_position = slider_length/2;
var percent_of_range = (range_input.value / (range_input.max - range_input.min));
var value_px_position = percent_of_range * slider_length;
var dist_from_center = value_px_position - center_position;
var percent_dist_from_center = dist_from_center / center_position;
var offset = percent_dist_from_center * half_thumb_width;
var final_label_position = value_px_position - half_label_width - offset;
I put together a quick demo of the problem and solution here: codepen demo
It was fun to figure out, but I hope this can help prevent others from spending the time.
This worked for me:
var slider = $("#combicalc_contribution-slider")[0];
var sliderPos = slider.value / slider.max;
var pixelPostion = slider.clientWidth * sliderPos;
//this is your pixel value
console.log(pixelPostion);
The pixel value was calculated properly for values from 1 to 50, on your example.
Here is an alternative solution, basically get the mouse position and use that instead of the slider position. (some tweaking required, possibly)
Fiddle here: https://jsfiddle.net/brightertools/qdhp2g17/5/
CSS:
.sliderHolder{
margin: 0;
padding: 0;
position: relative;
border: 1px solid silver;
#slider{
width: 100%;
}
.tt{
position: absolute;
border: 1px solid grey;
top: 20px;
margin: 5px;
}
}
HTML:
<div class="sliderHolder">
<input type="range" min="0" max="100" id="slider" />
</div>
JS:
var dragging = false;
jQuery('#slider').on('input',function(){
dragging = true;
});
jQuery('#slider').on('mouseup',function(){
dragging = false;
});
jQuery('#slider').on('mousemove',function(e){
if (dragging == false)
{
return;
}
jQuery('.tt').remove();
var mouseX = e.clientX - 14;
jQuery('.tt').remove();
var slider = jQuery('#slider');
var sliderValue = jQuery('#slider').val();
jQuery('.sliderHolder').append('<div class="tt">' + sliderValue + '</div>');
jQuery('.tt').css({'left':mouseX + 'px'});
})

Returning offsetWidth of element in percentage or with decimal places to make the width of an overlaying div the same - React / Javascript

Lately I am fiddling a bit in React and I have encountered the following problem, which is not necessarily React related but more Javascript / CSS in general related.
I have created a bar which contains a certain amount of cells. These cells all have the same width and height properties but will adjust its width/height properties to the viewport.
When I click one of these cells a div get's appended to the container of the cells, this div is an overlay with a different color (so you know which cell has been clicked).
The problem is that the bar and it's containing cells have their width attribute set in percentage, this has been done so I can calculate the width needed based on the total cell count when adding more cells to the containing div.
The overlay div however, which is added when a cell is being clicked, has it's width defined in px. This is because the left and top position of the overlay div is being determined with the pageY and pageX coordinates and the height and width of the cell element is being fetched with offsetHeight and offsetWidth.
The result of the above is that the actual width of the cell is a decimal value (it is percentage) but the calculated width is a rounded px value, this results in the following:
The normal Cell width:
The Overlay div width:
as you can see this is a minor difference in width, to show it properly I had to zoom in quite a bit. In the second picture you see that how further in left position the overlay div is being added, the bigger the difference (which is logical).
The code:
This is the normal Cell which is being rendered
_onRenderCell = (item, index) => {
this.myCell = React.createRef();
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={false}
style={{
width: 100 / this._columnCount + '%',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
... rest of the rendering omitted ...
You can see here that the width is determined based on the column count and returned as a percentage: width: 100 / this._columnCount + '%'
The onMouseDown event to add the overlay div:
_onMouseDown (e){
const containerNode = this.rsvnRef.current;
const cellNode = this.myCell.current;
// Determine current position
let posY = e.pageY - containerNode.getBoundingClientRect().top;
let posX = e.pageX - containerNode.getBoundingClientRect().left;
// Determine width and height of cell
let height = cellNode.offsetHeight;
let width = cellNode.offsetWidth;
// Determine top and left positions
let top = posY - (posY % height);
let left = posX - (posX % width);
var reservationClasses = document.getElementsByClassName('reservation');
var collisions = Array.prototype.filter.call(reservationClasses, function(rsv) {
return rsv.offsetTop == top && rsv.offsetLeft == left;
});
if (collisions.length == 0){
// Creating the overlay div
const newRsvn = document.createElement("div");
newRsvn.className = "reservation reservation-creating";
newRsvn.style.top = top + 'px';
newRsvn.style.left = left + 'px';
newRsvn.style.height = height + 'px';
newRsvn.style.width = width + 'px';
// Apending overlay div to container
containerNode.append(newRsvn);
}
}
My question is (as you probably expected); how can I make the overlaying div have the exact same width as the cell div? Can you return the offsetWidth with decimal places, or can I in some way calculate the offsetWidth in percentage?
After some more research, and thanks to this post: Converting width from percentage to pixels I managed to get it done.
However, I don't know if it is the best / right solution so please do give feedback if you think there is a better way!
I decided to just set the width of the cell in pixels instead of a percentage. The rendering of a cell is being done dynamically anyway (each time the screen size changes) so calculating the right amount of pixels in the cell rendering and rounding that to a whole number works fine since now both the cell and overlaying div are using the same width.
The code:
_onRenderCell = (item, index) => {
this.myCell = React.createRef();
const containerNode = this.rsvnRef.current;
let percents = parseInt(100 / this._columnCount);
let parentWidth = parseInt(containerNode.offsetWidth);
let pixels = parseInt(parentWidth*(percents/100));
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={false}
style={{
// width: 100 / this._columnCount + '%',
width: pixels + 'px',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
... rest of the rendering omitted ...

How to detect objects on the canvas with click event

Hi I am using a hashmap that allows me to efficiently detect objects in the given coordinates. However it is working perfectly , the problem lies with using the mouse to gather the position of the mouse within the canvas down to the pixel. I have been using the offsetX and offsetY methods for the event to gather some offset but it seems there is an offset I am unaware of and may have something to do with either:
1.using scaling on the canvas , Note: ive tried to fix this by division of the renderscale, this works with everything else so should be fine here.
mouseoffset is not accounting for parts of the page or is missing pixels at a low level (maybe 20) but divided by the render scale thats massive.
3.I am using a cartesian coordinate system to simplify things for the future , so the game map is in cartesian and may have to do with the problem.
I will not be supplying all the code because it is allot of work to go through it all so i will supply the following :
the html/css canvas code
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Game</title>
</head>
<body onload="jsEngine = new JsEngine(24, 24, .1); " >
<div class ="wrapper">
<canvas id="canvas" width="1920" height="1080"></canvas>
</div>
<style>
.wrapper {
position: relative;
width: auto;
height: 900px;
}
.wrapper canvas {
position: absolute;
left: 90px;
top: 50px;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 90%;
height: 90%;}
.GUI{
top: -315px;
left: -302px;
position: absolute;
width: 300px;
height: 300px;
background-color: cadetblue;
opacity: .5;
word-wrap: break-word;}
img{
image-rendering: optimize-contrast;
}
</style>
<div id = GUI class = "GUI"></div>
<!-- Libraries -->
<script src="../myapi/JSONE.js"></script>
<script src="../myapi/engine/SpacialHash.js"></script>
</body>
</html>
2.the javascript click function
//Click on objects
let onClick = function(event){
let canvas_ctx = document.getElementById("canvas").getContext("2d");
let canvasOffsetX = canvas_ctx.canvas.width/2;
let canvasOffsetY = canvas_ctx.canvas.height/2;
let mousePosX = event.clientX;
let mousePosY = event.clientY;
let mouseX =jsEngine.cameraFocus.x-canvasOffsetX/jsEngine.renderScale+(mousePosX)/jsEngine.renderScale;
let mouseY = jsEngine.cameraFocus.y+(canvasOffsetY)/jsEngine.renderScale+((-mousePosY)/jsEngine.renderScale);
console.log("sum to",mouseX,mouseY);
//My hashMap to place the mouse coordinates on the game map
let clickPosition = hm.find({x:mouseX,y:mouseY,width:1,height:1});
if(clickPosition.length===1){
let gameObject = jsEngine.gameObjects[clickPosition[0].range.id];
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY);
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
}else if(clickPosition.length>1) {
for (let i = 0; i < clickPosition.length; i++) {
let gameObject = jsEngine.gameObjects[clickPosition[i].range.id];
if (gameObject instanceof PlayerShip|| gameObject instanceof Bullet)
continue;
let clickBox = {};
let picture = gameObject.texture;
guiCreateClickBox(clickBox,gameObject.id,1200,500,picture);
//console.log(gameObject.transform.x,gameObject.transform.y,mouseX,mouseY)
}
}
};
// Listeners
//Click on objects
document.getElementById("canvas").addEventListener("click", onClick);
the making of the map and scale :Note: this is done via onPreRender
function drawBackground(canvas_ctx, renderScale, imageResource) {
let img = imageResource.mapBackground;
let mapWidth = 1000000;
let mapHeight= 1000000;
let zoom = 1;
mapWidth *= renderScale / zoom;
mapHeight *= renderScale / zoom;
// Render the Background
canvas_ctx.fillStyle = canvas_ctx.createPattern(img, 'repeat');
canvas_ctx.scale(zoom, zoom);
canvas_ctx.fillRect(-mapWidth / 2, - mapHeight / 2, mapWidth, mapHeight);
//if (jsEngine.cameraFocus.x > 1000000) {}
canvas_ctx.scale(1/zoom, 1/zoom);
}
The rendering method used for playership
renderGameObject(gameObject) {
let x = gameObject.transform.x * this.renderScale;
let y = -(gameObject.transform.y * this.renderScale);
let rotation = Math.radians(gameObject.transform.rotation);
let width = gameObject.transform.width;
width *= this.renderScale;
let height = gameObject.texture.height;
height *= this.renderScale;
// Render the gameObject
this.canvas_ctx.translate(x, y);
this.canvas_ctx.rotate(rotation);
this.canvas_ctx.drawImage(gameObject.texture, 0, 0, width / this.renderScale, height / this.renderScale, // Make sure the image is not cropped
-width/2 , // X
-height/2 , // Y
width, height); // width and height
this.canvas_ctx.rotate(-rotation);
this.canvas_ctx.translate(-x, -y);
}
the issue to solve is to make it so that when you click on any given quadrant of the canvas it will return -+ for top left, -- bottom left , -+ topright, +- bottomright, as well as being applied to the render scale which at the moment is .1 so just divide your mouse and canvas coords like shown above and you should be able to get the same results.
Things to keep in mind :
the jsEngine.cameraFocus is set to the playerships x and y coordinates(which are set to the 0,0 posiiton on the map) (which are also in the middle of the ship)
the top left of the canvas is still 0,0 and ++ is still toward the bottom right so theoretically minusing half the canvas width/height then adding the offsets X and Y. this should be working but at my map coordinate -4000,-4000 i get ~-3620,-3295 and at +4000,+4000 I get 3500,3500. (The reason why the canvas 0,0 is not where the ship is , is to make the ship in the middle of the screen)
If you have questions about anything based on code that needs to be supplied please ask via comment . Please note if you have problems with the format of the code supplied I have nothing to say about it . all I need is the click function working on the canvas model i set up in cartesian format.
ps: jQuery is not a solution its a problem please use vanilla js.
I found out why it was off , my canvas has a offset of 90 px and 50 px as well as the main problem that the canvas is only 90% of its origonal size (also in css). If anyone can give me help for how to adjust to these issues please reply in comment . until then I beleieve I have solved my own issue .

How get real positions of element in javascript

I want to get real X and Y position of my styled elements in javascript ( or jquery short code).
var offset = obj.offset();
ox=offset['left'];
oy=offset['top'];
px=parseInt(obj.css('padding-left')); // padding left
py=parseInt(obj.css('padding-top')); // padding top
bx=parseInt(obj.css('border-width') ); // stroke value
ox=ox+px+bx;
oy=oy+py+bx;
But this codes sometimes not work..
when scrool top or scroll left change im not get real position :(
please help me..
You don't have to use offsets. Use the modern getBoundingClientRect function:
function getPosition( element ) {
var rect = element.getBoundingClientRect();
return {
x: rect.left,
y: rect.top
};
}
You could then use the above function like this:
var element = document.getElementById( 'myElement' );
var pos = getPosition( el );
// Alert position in X axis
alert( pos.x );
// Alert position in Y axis
alert( pos.y );
Works in all browsers 🙂
EDIT: If you want the position of the element with respect to page scroll, just add document.body.scrollTop to Y position and document.body.scrollLeft to X position.
You'll want the offset from the element relative to the document. You have to keep in mind that styles like padding, margin and border can greatly affect the result of the offset. You might want to calculate those on or off the offset.
Finally you need to check if you are using box-sizing, which pushing padding and borders to the inside (with the most common version box-sizing: border-box;);
document.getElementById('cloud').offsetLeft; //offsetTop
Just debug with the other styles (adding/subtracting) until you get the real offset. I mostly test if the offset is correct by making a screenshot (or using the OS X selective-screenshot function) to see if the offset is correctly calculated (counting pixels) with the other styles.
Here's a little example:
CSS
#cloud {
height: 500px;
width: 500px;
margin: 20px auto;
border: 1px dotted #CCC;
}
HTML
<body>
<div id="cloud">
<div id="centerBox"></div>
</div>
</body>
JavaScript
'use strict';
console.log(document.getElementById('cloud').offsetLeft);
console.log(document.getElementById('cloud').offsetTop);
Ouput
main.js: 1 >>> 372
main.js: 2 >>> 20
Funny thing here, you can easily test if the offsetLeft works because of the margin: 20px auto;. If you resize the window it will also have a different offsetLeft.
This function gives you the exact position of an element without padding or margin or border:
function getElementRec(element) {
let rec = { x: 0, y: 0, width: 0, height: 0 };
let computedStyle = getComputedStyle(element);
rec.width = element.clientWidth;
rec.width -= parseFloat(computedStyle.paddingLeft);
rec.width -= parseFloat(computedStyle.paddingRight);
rec.height = element.clientHeight;
rec.height -= parseFloat(computedStyle.paddingTop);
rec.height -= parseFloat(computedStyle.paddingBottom);
let boundingRect = element.getBoundingClientRect();
rec.x = boundingRect.left;
rec.x += parseFloat(computedStyle.paddingLeft);
rec.x += parseFloat(computedStyle.borderLeft);
rec.y = boundingRect.top;
rec.y += parseFloat(computedStyle.paddingTop);
rec.y += parseFloat(computedStyle.borderTop);
return rec;
}
var offset = obj.offset();
ox=offset['left']; = document.getElementById('Mypicture').offsetLeft;
oy=offset['top']; = document.getElementById('Mypicture').offsetTop;
px=parseInt(obj.css('padding-left')); // padding left
py=parseInt(obj.css('padding-top')); // padding top
bx=parseInt(obj.css('border-width') ); // stroke value
ox=ox+px+bx;
oy=oy+py+bx;
//Two codes get equal value; But Not Real clientX ClientY positions..
// My html:
<div id="container">
<img id="Mypicture" src="myimage.jpg" alt="The source image for paint"/>
</div>
//My css :
#Mypicture{
margin:100px;
padding:20px;
border: 20px solid #cacaca;
}
#container {
display:block;
background:#ffaaff;
width: 550px;
padding:50px;
margin-left:300px;
}
// I want to get realx and realY value of Mypicture,on Document.
// All codes work Realx ( ox ) return true value But RealY (oy) nearly 10px false;

Positioning an element using values from Javascript variables

How to position an element for e.g. a div tag by using values for x & y co-ordinates from Javascript variables ?
If you're trying to position the object in absolute x,y coordinates on the page, just set the object to position: absolute and then set the values of top and left to your x and y.
HTML:
<div id="square" style="background-color: #777; height: 100px; width: 100px;"></div>
Code:
var s = document.getElementById("square");
s.style.position = "absolute";
var x = 100, y = 200;
s.style.left = x + "px";
s.style.top = y + "px";
You can see a working code example here: http://jsfiddle.net/jfriend00/hhpDQ/.
I'm not sure you can set the coordinates, but you could set the margin. Something like
$("#divid").css("margin-left" : "200px" , "margin-up" : "200px");

Categories