I am trying to move an HTML image (a black marker) to where I click on a map on the screen. The map has an onclick function which makes a marker visible and move to where the user clicks. However at the moment this only works for the size of screen I am using and whenever the window size is changed the image is several hundred pixels off on each axis.
At the moment I am storing the coordinates of a click in an array and using DOM style.left/top to change the position and using those coordinates plus a set amount of pixels that works for me, but not any other screen.
I would like a way to have it it move wherever the user clicks, regardless of the page dimensions.
This is the current way I am doing things, with coords being the array containing the relative coordinates:
document.getElementById('black-marker').style.visibility = 'visible';
document.getElementById('black-marker').style.left = coords[0]-20;
document.getElementById('black-marker').style.top = coords[1]+205;
Click in the red box and the black circle will move to the mouse point.
I got the position of the red box and the mouse position and used them to calculate the relative position for the black box.
const blackMarker = document.getElementById('black-marker');
const parent = blackMarker.parentElement;
parent.addEventListener('click', e => {
const {
x,
y,
width,
height
} = parent.getBoundingClientRect();
blackMarker.style.left = `${(e.clientX - x) / width * 100}%`;
blackMarker.style.top = `${(e.clientY - y) / height * 100}%`;
});
body {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
div {
position: relative;
width: 150px;
height: 150px;
background-color: red;
}
span {
position: absolute;
transform: translate(-50%, -50%);
width: 25px;
border-radius: 50%;
height: 25px;
background-color: black;
}
<div>
<span id="black-marker"></span>
</div>
Related
I am trying to get the coordinates of the box on the image. The coordinates should be based on the image itself and not on the screen size. I am currently using getBoundingClientRect(). How do I retrieve the coordinates based on the image, the box is on, rather than the window size?
CODE that I've tried:
var rect = div[index].getBoundingClientRect();
I found this post on SO : How to get xy coordinates of child element from parent element in jquery? but it was 7 years ago...
You would use the difference between the elements position and its containers position. I've used getBoundingClientRect and returned a new DomRect like you were trying but be cautions as there is no support for Internet Expolorer, Edge or Safari at the moment.
const getBoundingClientRect_RelativeToParent = element => {
const domRect = element.getBoundingClientRect(),
parentDomRect = element.parentElement.getBoundingClientRect()
return new DOMRect(domRect.left - parentDomRect.left, domRect.top - parentDomRect.top, domRect.width, domRect.height)
}
console.log(getBoundingClientRect_RelativeToParent(document.querySelector(".child")))
.parent {
width: 500px;
height: 300px;
margin-left: 200px;
margin-top: 200px;
padding-left: 30px;
padding-top: 30px;
background: green;
}
.child {
width: 100px;
height: 50px;
background: red
}
body {
background: blue
}
<div class="parent">
<div class="child">
</div>
</div>
I use images created on the fly to maintain the aspect ratio of boxes with a fixed height. Image sources are set as data-urls provided from a canvas with a given width and height, the images are then attached to divs which can contain any content, have any height, and still maintain a fixed aspect ratio.
This works well, however, on slower phones with less memory the large number of data-urls on the page can start to be a little bit of a drag. Some of the ratios can't be reduced below a certain point resulting in relatively large canvases.
Is there any way to set the ratio of an img element without setting its source? Is there any way to set the source to a format that is an truly empty image with only a width and height?
EDIT: The snippet below throws an error - iframe restrictions, probably having to do with making images. You can see an error free version over at this CodePen.
const wrapper = document.querySelector(".wrapper");
function addRatioBox(width, height = 1) {
const cvs = document.createElement("canvas");
const img = new Image(width, height);
const box = document.createElement("div");
cvs.width = width;
cvs.height = height;
img.src = cvs.toDataURL("image/png");
box.appendChild(img);
box.className = "ratioBox";
wrapper.appendChild(box);
}
addRatioBox(1);
addRatioBox(4, 3);
addRatioBox(16, 9);
addRatioBox(2, 1);
.ratioBox {
background: orange;
display: inline-block;
height: 100%;
margin-right: 10px;
}
.ratioBox img {
height: 100%;
width: auto;
display: block;
}
/* just a whole bunch of stuff to make things prettier from here on down */
.wrapper {
background: #556;
padding: 10px;
position: absolute;
height: 20%;
top: 50%;
left: 50%;
white-space: nowrap;
transform: translate(-50%, -50%);
}
body {
background: #334;
}
.ratioBox:last-of-type {
margin-right: 0;
}
<div class="wrapper"></div>
I am trying to change my cursor into different images depending on the object that it is hovering over inside my banner. Currently I only know to change the cursor style in CSS. But the cursor stays the same throughout. How do I replace the cursor image on mouseover in my javascript? I am only using jQuery and TweenMax as this is for an assignment.
Using CSS cursor property
Without using any pseudo-selectors in CSS, you can have a pretty good result by playing around with the cursor property. For example, you can select one cursor style from a range of available ones. Or even add your own by linking the URL of the icon.
For example, the code below will show a heart when you hover over the grey area:
.heart {
cursor: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/9632/heart.png"), auto;
width: 200px;
height: 200px;
background: grey;
}
<div class="heart"></div>
You can change the origin of the image's position relative to the actual mouse position by setting the x and y position along with the URL in the cursor property:
cursor: url(<URL>) [x y|auto];
Using JavaScript
Of course, you can handle this feature with JavaScript code. Here are several things we will need to achieve this:
creating an HTML element with the image of the cursor you want as background
using the onmouseenter, onmousemove and onmouseleave events
getting the position of the mouse on the page: properties pageX, pageY
setting the position of our cursor element to be at the position of the mouse (the actual mouse pointer will be hidden): with the transform CSS property.
There are several other tricks I have used to get it right: for example setting the boxes' overflow to be hidden so that the cursor elements can't be seen outside the box. Also, listening to the onmouseleave event allows us to hide the cursor element when the mouse is outside the box area.
I have made a little demo here, click Show code snippet > Run code snippet:
const showCursor = function(event) {
let cursor = event.target.querySelector('.cursor');
event.target.onmousemove = function(e) {
cursor.style.display = 'block'
let [x, y] = [e.pageX - e.target.offsetLeft - 20, e.pageY - e.target.offsetTop - 20]
cursor.style.transform = `translate(${x}px, ${y}px)`
}
event.target.onmouseleave = function(e) {
cursor.style.display = 'none'
}
}
.box {
cursor: none;
overflow: hidden;
width: 200px;
height: 200px;
background: pink;
display: inline-block;
margin: 10px;
}
.box:nth-child(1) {
background: aquamarine;
}
.box:nth-child(2) {
background: pink;
}
.box:nth-child(3) {
background: cornflowerblue;
}
.box:nth-child(4) {
background: lightcoral;
}
.cursor {
display: none;
width: 100px;
height: 100px;
}
#heart {
background: no-repeat url("https://png.icons8.com/color/50/000000/hearts.png");
}
#diamond {
background: no-repeat url("https://png.icons8.com/color/50/000000/diamonds.png")
}
#spade {
background: no-repeat url("https://png.icons8.com/metro/50/000000/spades.png")
}
#clubs {
background: no-repeat url("https://png.icons8.com/ios/50/000000/clubs-filled.png")
}
<div onmousemove="showCursor(event)" class="box">
<div id="diamond" class="cursor"></div>
</div>
<div onmouseenter="showCursor(event)" class="box">
<div id="heart" class="cursor"></div>
</div>
<div onmousemove="showCursor(event)" class="box">
<div id="spade" class="cursor"></div>
</div>
<div onmousemove="showCursor(event)" class="box">
<div id="clubs" class="cursor"></div>
</div>
The function showCursor() is called when the user's mouse enters one of the boxes with the attribute onmouseenter="showCursor(event)" (see HTML markup above).
Below I have provided the JavaScript code with comments explaining how it works:
const showCursor = function(event) {
// get the element object of the cursor of this box
let cursor = event.target.querySelector('.cursor');
// function that will be execute whenever the user moves inside the box
event.target.onmousemove = function(e) {
// the user is moving inside the box
// show the cursor element
cursor.style.display = 'block'
// calcultate the translate values of the cursor element
let [x, y] = [e.pageX - e.target.offsetLeft - 20, e.pageY - e.target.offsetTop - 20]
// apply these values to the style of the cursor element
cursor.style.transform = `translate(${x}px, ${y}px)`
}
// function that will be executed when the user leaves the box
event.target.onmouseleave = function(e) {
// the user's mouse left the box area
// hide the cursor element
cursor.style.display = 'none'
}
}
With a <svg> element
A while ago I answered a post on how to add an <svg> element as the cursor of the mouse. It's a little bit more advanced though. It's still a JavaScript solution but it involves using a <svg> element as the cursor instead of it being a simple <div> (as seen in the second point).
After 4 hours of trial and errors, I cannot find a way to get the width of the circle that is defined by a percent and convert it to pixels and make the circles height the same size as the width in pixels. Below is what I have right now. (I have tried many variations of this but cannot figure it out) Right now it only works on my screen. I try it on other devices and the height is just not right. This button is created onload.
Example: Circle Width = 12% , the Pixel Value of 12% on a screen is "70px". So somehow make Circle Height = 70px.
<!DOCTYPE html>
<head>
<title>Circle Test</title>
<meta charset='UTF-8'>
<script type="text/javascript" src="/js/fs"></script>
</head>
<body>
</body>
</html>
// Creates a button
var mainButton = document.createElement("button");
mainButton.style.width = "10%";
// Get the Screens Avaliable Width and Get 10% of it and convert it to pixels
var wad = screen.availWidth * .1 + "px";
// Thinking this would return the pixel amount the circle button is, but it only works on the regular screen and not when resized. It also does not work for mobile.
console.log(wad);
mainButton.style.height = wad;
You set the width of your button to 10% of its containing block's width, and the height to 10% of the width of one of
The available area of the rendering surface of the output device, in CSS pixels.
The area of the output device, in CSS pixels.
The area of the viewport, in CSS pixels.
It's very likely that these are measurements of two different things, or that resizing the window will affect one but not the other. Fortunately, CSS has a unit for "percentage of the window's width": vw. Set your button's height and width in vw units, and you don't need any JavaScript:
button {
width: 10vw;
height: 10vw;
border-radius: 50%;
}
<button>Go</button>
If you really meant that the button is 10% as wide as its container, even if its container isn't as wide as the whole window, you can use the padding-bottom technique detailed in this answer. Unlike height, percentages in padding refer to the width of the containing block:
.wrapper {
width: 40%; /* here I use 40% instead of 10% for aesthetics */
padding-bottom: 40%; /* should match width */
position: relative;
}
.wrapper > button {
display: block;
position: absolute;
width: 100%;
top: 0;
bottom: 0;
border-radius: 50%;
}
/* the rest is just to make figuring out
the exact width of the button difficult */
body {
display: flex;
align-items: stretch;
height: 90vh;
}
body > div {
flex: 1 1 0;
background: rebeccapurple;
margin: 0 4px;
}
<div>
<div class="wrapper"><button>Go</button></div>
</div>
<div></div>
<div></div>
And finally, just for completeness, if you really must get the computed width from JavaScript, you can use window.getComputedStyle:
let button = document.querySelector('button');
let width = window
.getComputedStyle(button)
.getPropertyValue('width');
console.log(button.style.height = /* DO NOT DO THIS */ width);
button {
width: 40%;
border-radius: 50%;
}
/* the rest is just to make figuring out
the exact width of the button difficult */
body {
display: flex;
align-items: stretch;
height: 90vh;
}
body > div {
flex: 1 1 0;
background: rebeccapurple;
margin: 0 4px;
}
<div>
<button>Go</button>
</div>
<div></div>
<div></div>
If you try putting that into a resize handler, though, performance will suffer.
JSFiddle code
I am trying to get hold of div with blue lines when I move the mouse pointer within a distance of 20px from the div. I am able to get hold of the div with blue lines only when the mouse pointer is on that div. Basically, selecting a div using the mouser pointer is difficult as the div width is only 1px which cannot be changed.
I am executing the below code but still not able to catch hold of the div which is 20px away from either right or left of the mouse pointer.
Note:The div mentioned above indicated the div with blue lines and not the gray box.
//Div positions and their id has been added to map
var hmap = new Map();
hmap.set("hguide1",96);
hmap.set("hguide2",284);
hmap.set("hguide3",520);
var vmap = new Map();
vmap.set("vguide1", 96);
vmap.set("vguide2",384);
vmap.set("vguide3",720);
$(document).mousemove(function(e){
var mx = e.pageX, my = e.pageY;
//Catch hold of vertical div's
for (var [key, value] of vmap) {
var dist = value - mx;
if(dist >= -20 && dist <= 20){
$('.'+key).css({width: '10px', left:});
} else {
$('.'+key).css({width: '1px'});
}
}
//Catch hold of horizontal div's
for (var [key, value] of hmap) {
var dist = value - my;
if(dist >= -20 && dist <= 20){
$('.'+key).css({height: '10px'});
} else {
$('.'+key).css({height: '1px'});
}
}
});
I looking for a way thru which I can catch hold of the div, which is 20px away from either the left or right side of the mouse pointer, and drag it.
Any suggestions much appreciated.
You can use CSS styling to get this result. We set the ::after size to 100% - 20px on either the left or top, depending if it's the horizontal or vertical line. We then set our width or height, depending on if we're adjusting the row or column, to either 100% or the buffer size(40px, because we want 20px on either side of the line).
I realize that sounds a little confusing, so I'll split them up. Here's the vertical:
.vguide1,.vguide2,.vguide3 {
border-left: 1px solid blue;
padding-bottom: 20px;
position: absolute;
width:1px;
height:650px;
}
.vguide1::after,.vguide2::after,.vguide3::after {
content: '';
position: absolute;
left: calc(50% - 20px);
width: 40px;
height: 100%;
cursor: col-resize;
}
Horizontal:
.hguide1,.hguide2,.hguide3 {
padding-right: 20px;
position: absolute;
width:850px;
height:1px;
border-top: 1px solid blue;
}
.hguide1::after,.hguide2::after,.hguide3::after {
content: '';
position: absolute;
top: calc(50% - 20px);
width: 100%;
height: 40px;
cursor: row-resize;
}
With shading to show the hit box: https://jsfiddle.net/Ljxpj5bt/27/
Without hit box: https://jsfiddle.net/Ljxpj5bt/28/