Why I am getting wrong cursor position when scaling entire body? - javascript

I'm scaling the entire using a CSS scale transform. The problem is that I get the wrong cursor position. I want to create a new div where the cursor is clicked but div is being created in wrong position.
$(document).ready(function() {
$('body').css({
transform: 'scale(0.5,0.5)'
});
var k = 1;
$('.container').off('click').on('click', function(e) {
var top = e.pageY;
var left = e.pageX;
$('<div />', {
id: 'temp' + k
}).css({
position: 'absolute',
top: top + 'px',
left: left + 'px',
width: '50px',
height: '50px',
border: '1px solid red'
}).appendTo('.container');
k++;
});
});

Related

Creating a popup menu with bookmarklets

This is my first question, so please give me any pointers on how I could ask better ones.
Anyway, how would I make a togglable menu that displays links, that activates using a bookmarklet. I have tried to find answers, but all were fruitless. Would I need to create a new element for this?
You will need to create the pop-up menu using vanilla JS. I also implemented drag functionality. The only thing this needs is to correctly set the position when a page is scrolled.
DOM layout
The most important elements and styles below are required.
<div style="position:absolute; z-index:2147483647">
<div style="position: relative">
<div style="position:relative; display:inline-block; left:0">Bookmarklet Links</div>
<div style="position:relative; float:right">×</div>
</div>
<div>
<p>Click the links to open a new tab!</p>
<ul>
<li>
Google
</li>
<li>
Bing
</li>
<li>
DuckDuckGO
</li>
</ul>
</div>
</div>
You can save the following bookmarklet:
javascript:!function(){var c=0x1f4,d=0x12c,e='#AAA',f=0x1,g=0x20,h='#444',i='#FFF',j='Bookmarklet\x20Links',k=~~(document['documentElement']['clientWidth']/0x2-c/0x2),l=~~(document['documentElement']['clientHeight']/0x2-d/0x2),m=~~(0.8*g),n=document['createElement']('DIV');Object['assign'](n['style'],{'position':'absolute','left':k+'px','top':l+'px','zIndex':Number['MAX_SAFE_INTEGER'],'width':c+'px','height':d+'px','background':e,'border':f+'px\x20solid\x20black'});var o=document['createElement']('DIV');Object['assign'](o['style'],{'position':'relative','width':c+'px','height':g+'px','background':h,'borderBottom':f+'px\x20solid\x20black'});var p=document['createElement']('DIV');Object['assign'](p['style'],{'position':'relative','display':'inline-block','left':0x0,'width':~~(c-0x2*m)+'px','lineHeight':g+'px','color':i,'fontSize':~~(0.667*g)+'px','marginLeft':~~(m/0x3)+'px'}),p['textContent']=j;var q=document['createElement']('DIV'),r=~~((g-m)/0x2);Object['assign'](q['style'],{'position':'relative','float':'right','right':r+'px','top':r+'px','width':m+'px','height':m+'px','background':'#F00','border':f+'px\x20solid\x20black','color':'#FFF','lineHeight':m+'px','textAlign':'center','fontSize':m+'px','marginLeft':'auto','marginRight':0x0});var s=document['createElement']('DIV');Object['assign'](s['style'],{'padding':'1em'});var t=document['createElement']('P');t['textContent']='Click\x20the\x20links\x20to\x20open\x20a\x20new\x20tab!',s['appendChild'](t);var u=document['createElement']('UL');[{'name':'Google','url':'https://www.google.com'},{'name':'Bing','url':'https://www.bing.com'},{'name':'DuckDuckGO','url':'https://duckduckgo.com'}]['forEach'](c=>{var d=document['createElement']('LI'),e=document['createElement']('A');e['setAttribute']('href',c['url']),e['setAttribute']('target','_blank'),e['textContent']=c['name'],d['appendChild'](e),u['appendChild'](d);}),s['appendChild'](u),q['addEventListener']('click',function c(d){q['removeEventListener']('click',c,!0x1);o['removeChild'](q);n['removeChild'](o);n['removeChild'](s);document['body']['removeChild'](n);},!0x1),q['textContent']='×',o['appendChild'](p),o['appendChild'](q),n['appendChild'](o),n['appendChild'](s),document['body']['appendChild'](n),function(c){var d=function(c){var d=c['getBoundingClientRect'](),e=window['pageXOffset']||document['documentElement']['scrollLeft'],f=window['pageYOffset']||document['documentElement']['scrollTop'];return{'top':d['top']+f,'left':d['left']+e};}(c['parentElement']),e=!0x1,f={'x':0x0,'y':0x0},g={'x':d['left'],'y':d['top']};c['parentElement']['addEventListener']('mousedown',function(d){e=!0x0,f['x']=d['clientX'],f['y']=d['clientY'],c['parentElement']['style']['cursor']='move';}),c['parentElement']['addEventListener']('mouseup',function(d){e=!0x1,g['x']=parseInt(c['parentElement']['style']['left'])||0x0,g['y']=parseInt(c['parentElement']['style']['top'])||0x0,c['parentElement']['style']['cursor']='auto';}),document['addEventListener']('mousemove',function(d){if(!e)return;var h={'x':d['clientX']-f['x'],'y':d['clientY']-f['y']},i={'x':g['x']+h['x'],'y':g['y']+h['y']};i['x']<0x0?i['x']=0x0:i['x']+c['parentElement']['offsetWidth']>document['documentElement']['clientWidth']&&(i['x']=document['documentElement']['clientWidth']-c['parentElement']['offsetWidth']);i['y']<0x0?i['y']=0x0:i['y']+c['parentElement']['offsetHeight']>document['documentElement']['clientHeight']&&(i['y']=document['documentElement']['clientHeight']-c['parentElement']['offsetHeight']);c['parentElement']['style']['left']=i['x']+'px',c['parentElement']['style']['top']=i['y']+'px';});}(o);}(window);
Method of minification and obfuscation
I minified the code below using: https://javascript-minifier.com/
I obfuscated the resulting minified code using: https://obfuscator.io/
For the obfuscator, I set "Identifier Names Generator" to "mangled" and checked "Rename Globals".
Important: Unselect "String Array" or you cannot add new link entries.
Caveats
The script doesn't allow moving beyond the initial width and height. The following width and height methods from this post could be incorporated to fix this limitation.
Source code
(function(window) {
var links = [{
name: 'Google',
url: 'https://www.google.com'
}, {
name: 'Bing',
url: 'https://www.bing.com'
}, {
name: 'DuckDuckGO',
url: 'https://duckduckgo.com'
}];
var props = {
width: 500,
height: 300,
background: '#AAA',
borderThickness: 1,
headerHeight: 32,
headerBackground: '#444',
headerTitleColor: '#FFF',
windowTitle: 'Bookmarklet Links'
};
var windowPosition = {
left: ~~((document.documentElement.clientWidth / 2) - (props.width / 2)),
top: ~~((document.documentElement.clientHeight / 2) - (props.height / 2)),
}
var btnSize = ~~(props.headerHeight * 0.8);
var popupEl = document.createElement('DIV');
Object.assign(popupEl.style, {
position: 'absolute',
left: windowPosition.left + 'px',
top: windowPosition.top + 'px',
zIndex: Number.MAX_SAFE_INTEGER,
width: props.width + 'px',
height: props.height + 'px',
background: props.background,
border: props.borderThickness + 'px solid black'
});
var popupHeader = document.createElement('DIV');
Object.assign(popupHeader.style, {
position: 'relative',
width: (props.width) + 'px',
height: props.headerHeight + 'px',
background: props.headerBackground,
borderBottom: props.borderThickness + 'px solid black'
});
var popupHeaderTitle = document.createElement('DIV');
Object.assign(popupHeaderTitle.style, {
position: 'relative',
display: 'inline-block',
left: 0,
width: ~~(props.width - btnSize * 2) + 'px',
lineHeight: props.headerHeight + 'px',
color: props.headerTitleColor,
fontSize: ~~(props.headerHeight * 0.667) + 'px',
marginLeft: ~~(btnSize / 3) + 'px'
});
popupHeaderTitle.textContent = props.windowTitle;
var closeButton = document.createElement('DIV');
var margin = ~~((props.headerHeight - btnSize) / 2);
Object.assign(closeButton.style, {
position: 'relative',
float: 'right',
right: margin + 'px',
top: margin + 'px',
width: btnSize + 'px',
height: btnSize + 'px',
background: '#F00',
border: props.borderThickness + 'px solid black',
color: '#FFF',
lineHeight: btnSize + 'px',
textAlign: 'center',
fontSize: btnSize + 'px',
marginLeft: 'auto',
marginRight: 0
});
var popupBody = document.createElement('DIV');
Object.assign(popupBody.style, {
padding: '1em'
});
var p = document.createElement('P');
p.textContent = 'Click the links to open a new tab!';
popupBody.appendChild(p);
var listEl = document.createElement('UL');
links.forEach(link => {
var itemEl = document.createElement('LI');
var anchorEl = document.createElement('A');
anchorEl.setAttribute('href', link.url);
anchorEl.setAttribute('target', '_blank');
anchorEl.textContent = link.name;
itemEl.appendChild(anchorEl);
listEl.appendChild(itemEl);
});
popupBody.appendChild(listEl);
closeButton.addEventListener('click', destroyWindow, false);
closeButton.textContent = '×';
popupHeader.appendChild(popupHeaderTitle);
popupHeader.appendChild(closeButton);
popupEl.appendChild(popupHeader);
popupEl.appendChild(popupBody);
document.body.appendChild(popupEl);
draggable(popupHeader);
function destroyWindow(e) {
closeButton.removeEventListener('click', destroyWindow, false);
popupHeader.removeChild(closeButton);
popupEl.removeChild(popupHeader);
popupEl.removeChild(popupBody);
document.body.removeChild(popupEl);
}
/* Source: https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/ */
function offset(el) {
var rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
}
/* Source: https://gist.github.com/remarkablemark/5002d27442600510d454a5aeba370579 */
function draggable(el) {
var initialOffset = offset(el.parentElement);
var isMouseDown = false;
var currPos = { x : 0, y : 0 };
var elPos = { x : initialOffset.left, y : initialOffset.top };
el.parentElement.addEventListener('mousedown', onMouseDown);
function onMouseDown(event) {
isMouseDown = true;
currPos.x = event.clientX;
currPos.y = event.clientY;
el.parentElement.style.cursor = 'move';
}
el.parentElement.addEventListener('mouseup', onMouseUp);
function onMouseUp(event) {
isMouseDown = false;
elPos.x = parseInt(el.parentElement.style.left) || 0;
elPos.y = parseInt(el.parentElement.style.top) || 0;
el.parentElement.style.cursor = 'auto';
}
document.addEventListener('mousemove', onMouseMove);
function onMouseMove(event) {
if (!isMouseDown) return;
var delta = { x : event.clientX - currPos.x, y: event.clientY - currPos.y };
var pos = { x : elPos.x + delta.x, y : elPos.y + delta.y };
if (pos.x < 0) {
pos.x = 0;
} else if (pos.x + el.parentElement.offsetWidth > document.documentElement.clientWidth) {
pos.x = document.documentElement.clientWidth - el.parentElement.offsetWidth;
}
if (pos.y < 0) {
pos.y = 0;
} else if (pos.y + el.parentElement.offsetHeight > document.documentElement.clientHeight) {
pos.y = document.documentElement.clientHeight - el.parentElement.offsetHeight;
}
el.parentElement.style.left = pos.x + 'px';
el.parentElement.style.top = pos.y + 'px';
}
}
})(window);
Improving
You will notice that if your cursor goes off-screen while dragging (and you release the button) the window will be stuck in drag. You could detect this globally, but you will also need to figure out how re reinitialize the position to last known "good" position.
document.addEventListener('mouseup', onGlobalMouseUp);
function onGlobalMouseUp(event) {
if (
(event.clientX < 0 || event.clientX > document.documentElement.clientWidth) ||
(event.clientY < 0 || event.clientY > document.documentElement.clientHeight)
) {
if (isMouseDown) {
isMouseDown = false; // Draggged off-screen
popupEl.style.cursor = 'auto';
}
}
}
Lastly, don't spam the bookmarklet button, because it will create multiple instances of the same window. Code can be added to detect the presence of the window before creating a new one. Closing it could hide it, so it will just make the existing one visible again. Multiple windows will break the close listener.

Change navbar-fixed position when scrolling in MaterializeCSS

Fist of all, sorry for my bad english.
I've this site with a company logo at the top and a navbar down it. I wanna change the navbar position to the top when I scroll past the company logo.
I try to change it with CSS in:
.navbar-fixed {
position: relative;
height: 56px;
z-index: 1000;
}
to...
.navbar-fixed {
position: top;
height: 56px;
z-index: 1000;
}
using Materialize.js on the $(document).ready(function (){}) with the next algorhythm:
var scroll_start = 0;
var startchange = $('#startchange');
var offset = startchange.offset();
if (startchange.length){
$(document).scroll(function() {
scroll_start = $(this).scrollTop();
if(scroll_start > offset.top) {
$(".navbar-fixed").css('position', 'top');
} else {
$('.navbar-fixed').css('position', 'relative');
}
});
}
but it didn't works.
First of all, css property position doesn't have top value.
Okay, here's a script taken 3 minutes of my time. I believe you can easily improve it to let it suit your needs. Say your company logo has id="logo":
function fixNavbar() {
var $logo = $('#logo'),
$nav = $('.navbar-fixed'),
offset = $logo.offset(),
logoHeight = $logo.height(),
distance = offset + logoHeight,
scroll = $(window).scrollTop();
if (scroll >= distance) {
$nav.css({
'position': 'fixed',
'top': '0',
'right': '0',
'left': '0'
});
} else {
$nav.css({
'position': 'relative',
'top': 'auto',
'right': 'auto',
'left': 'auto'
});
}
}
$(window).scroll( function() {
fixNavbar();
});

set multiple animation on single element, when trigger them one by one

I want to set multiple animation on single element on the phone, when trigger them one by one. I achieve this by the under method , but have 2 problems:
I need accurate position and size, so I use top bottom width height. But I know use these properties, the browser need to render again, so it is not efficient.
On the second animation, although I set animation-fill-mode: forwards, but still need to set 0% keyframes to assure second animation start point is on the first animation end point.
Thanks for more efficient method.
my demo
html:
<button id="first">first</button>
<button id="second">second</button>
<div class="moon"></div>
css:
.first {
animation-name: first;
}
.second {
animation-name: second;
}
#-webkit-keyframes first {
100% {
height: 2.5rem;
width: 2.5rem;
left: 4.1rem;
bottom: 11.7rem;
}
}
#-webkit-keyframes second {
0% {
height: 2.5rem;
width: 2.5rem;
left: 4.1rem;
bottom: 11.7rem;
}
100% {
height: 4rem;
width: 4rem;
left: 5.8rem;
bottom: 10.5rem;
}
}
js:
var $moon = $('.moon');
$('#first').click(function() {
$moon.addClass('animated first');
});
$('#second').click(function() {
$moon.addClass('animated second');
});
You might want to try with the JQuery keyframe plugin, you can download it here:
https://github.com/Keyframes/jQuery.Keyframes
You can then initialize a set of variables such as height width top and left like this:
var $moon = $('.moon'),
newHeight = '0',
newWidth = '0',
newTop = '0',
newLeft = '0';
And then for the clicks you could try dynamic variables for each click incrementing 40 each time it clicks?
$('#first').click(function() {
newHeight = $moon.height() + 40+'px';
newWidth = $moon.width() + 40+'px';
newTop = $moon.position().top + 80+'px';
newLeft = $moon.position().left + 80+'px';
$moon.removeClass('first');
$moon.removeClass('second');
$.keyframe.define([{
name: 'first',
'0%': {'height': $moon.height()+'px',
'width': $moon.width() +'px',
'left': $moon.position().left+'px',
'top': $moon.position().top+'px'
},
'100%': {'height': newHeight,
'width': newWidth,
'left': newLeft,
'top': newTop
}
}]);
$moon.addClass('first');
});
$('#second').click(function() {
newHeight = $moon.height() + 40+'px';
newWidth = $moon.width() + 40+'px';
newTop = $moon.position().top + 80+'px';
newLeft = $moon.position().left + 80+'px';
$moon.removeClass('first');
$moon.removeClass('second');
$.keyframe.define([{
name: 'second',
'0%': {'height': $moon.height()+'px',
'width': $moon.width()+'px',
'left': $moon.position().left+'px',
'top': $moon.position().top+'px',
},
'100%': {'height': newHeight,
'width': newWidth,
'left': newLeft,
'top': newTop,
}
}]);
$moon.addClass('second');
});
Thought you might give that a try, Leo.

Create a DIV at click; Then remove same DIV by clicking on it

I'm very new to programming and particularly JS and JQuery.
I've searched SO for hours trying to figure out how to do this seemingly simple task and observed plenty of code from talented programmers, but nothing what would suit my request.
I'm simply trying to
(A) create a dynamic DIV at the point on the page where the user clicks the mouse. This part I can accomplish.
(B) The next step is clicking on that new DIV and removing it from the page.
Here's what I've found to accomplish step A:
$(function(){
$('#picture').click(function(e){
var x = e.pageX - 20 + 'px';
var y = e.pageY - 20 + 'px';
var div = $('<div>', {
'class':'face',
'css': {
'position':'fixed',
'left': x,
'top': y,
'width': '40px',
'height': '40px'
},
});
$(document.body).append(div);
This simply creates a small 40x40px DIV in the body of the document.
Step B is proving beyond my knowledge. Simply being able to click on that newly created DIV and remove it from the document?
If I create the same div manually prior to the page loading, I can click it as expected. I just cant find a way to 'find' the newly created DIV's. Please help. I have researched extensively, and cant seem to find out how to accomplish this.
jsbin demo
Use dynamic event delegation with the .on() method
$("body").on("click", ".face", function(){
$(this).fadeOut(function(){
$(this).remove();
});
});
http://api.jquery.com/on/#direct-and-delegated-events
P.S: to prevent dispatching events all over the document or "body" use rather the first static parent ID as selector $("#someid").on.
or as Santiago suggested (but slightly different), accessing the "click" Element property and not using the div variable at all:
$('#picture').click(function(e) {
var x = e.pageX - 20 + 'px';
var y = e.pageY - 20 + 'px';
$('<div />', { // Don't forget closign slash!
'click': function(){ // The click property
$(this).fadeOut(function(){
$(this).remove();
});
},
'class':'face',
'css': {
position: 'fixed',
left: x,
top: y,
width: 40,
height: 40
}
}).appendTo("body");
});
jsbin demo
what about this:
$(function(){
$('#picture').click(function(e) {
var x = e.pageX - 20 + 'px';
var y = e.pageY - 20 + 'px';
var div = $('<div>', {
'class':'face',
'css': {
'position':'fixed',
'left': x,
'top': y,
'width': '40px',
'height': '40px'
},
'click': function(ev) {
$(ev.target).remove();
}
});
$("body").append(div);
});
});
#picture {
height: 150px;
width: 150px;
background:gray;
display:block;
}
.face {
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="picture"></div>
It's pretty simple actually. Add a function to your javascript to remove the element after you create it. You can do it even more easily thanks to jQuery. I think that my answer is one of the most elegants here ;P hihi
div.click(function(){
div.remove();
});
I did a live example below, if you want to test it :)
$(function(){
$('#picture').click(function(e){
var x = e.pageX - 20 + 'px';
var y = e.pageY - 20 + 'px';
var div = $('<div>', {
'class':'face',
'css': {
'position':'fixed',
'left': x,
'top': y,
'width': '40px',
'height': '40px'
},
});
/* HELLO DEAR, I DO THE TRICK */
div.click(function(){
div.remove();
});
$(document.body).append(div);
});
});
#picture{
width:500px;
height:500px;
background-color:green;
}
.face {
background-color:red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="picture">
</div>
Use event delegation:
$(document).on('click', '.face', function(){
$(this).remove();
});
$(function(){
$('#picture').click(function(e){
var x = e.pageX - 20 + 'px';
var y = e.pageY - 20 + 'px';
var div = $('<div/>', {
'class':'face',
'css': {
'position':'fixed',
'left': x,
'top': y,
'width': '40px',
'height': '40px'
}
});
$(document.body).append(div);
});
});
$(document).on('click','.face', function() {
$(this).remove();
});
#picture {
width: 200px;
height: 200px;
border: 1px solid black;
}
.face {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="picture"></div>
I would create the jQuery object first, then you can append and remove it at will, without creating a new jQuery object.
In the image click listener all the script below does is change the position of the square and append it if it isn't already appended, while clicking on the square itself will remove it.
$(function(){
var body = $('body');
var div = $('<div>', {
'class':'face',
'css': {
'position':'fixed',
'width': '40px',
'height': '40px',
'background': '#f9fd42',
}
});
$(document).on('click', function(e){
if(div.is(e.target)) div.remove();
});
$('#demo').click(function(e){
div.css({
'left': e.pageX - 20 + 'px',
'top': e.pageY - 20 + 'px'
}).appendTo(body);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="//lorempixel.com/200/100" id="demo">
<div class="full-page">
<div class="imgbox">
</div>
</div>
js
$('.imgbox').click(function(e){
var x=e.pageX-20;
var y=e.pageY-20;
var ap_div='<div class="ap_div" style="left:'+ x +'px;top:'+ y+'px"></div>';
$('.full-page').append(ap_div)});
$('body').delegate(".ap_div", 'click', function(e){
$(this).remove();
});
fiddle
http://jsfiddle.net/6czbzb38/2/

How do I position a div relative to the mouse pointer exactly when scroll page?

I found this example on my search.
But it is useless, because when the webpage has long height, and my <div> block isn't on the top, when I scroll the page, there are different distances with different PageY or clientY, so the movable <div> can not exactly go after the mouse cursor.
Here's what I've tried so far:
jQuery("#requestStatusChart").mouseover(function (event) {
var maskVal = '<span id="floatTip" style="position:absolute"><span id="hintdivlogistics" class="RMAHintdivlogistics">' +
+'</span><div class="clear"></div></span>';
jQuery(this).find(".DashboardMask").append(maskVal)
ShowHintInfoLogistics("abc");
//when onmouse out ,remove the elements I appended before.
jQuery(this).find(".DashboardMask").mouseout(function () {
if (typeof jQuery("#hintdivlogistics") != undefined) {
jQuery("#floatTip").fadeOut("slow").remove();
}
});
//move current row
jQuery(this).find(".DashboardMask").mousemove(function (event) {
_xx = event.clientX;
_yy = event.clientY;
_yyPage = event.pageY;
var pos = jQuery(this).position();
console.log((pos.left + " " + pos.top));
jQuery("#floatTip").css({ "top": _yy + "px", "left": _xx - 180 + "px",
"border": "2px solid red"
}).fadeIn("slow");
console.log("x:" + _xx + ",y:" + _yy / _yyPage * _yy);
return false;
});
return false;
});
I don't know of any way to do that reliably, given that you don't know the position of the mouse without a mouse event. You could keep track of the mouse position on mousemove, but as this snippet demonstrates it's far from ideal.
function mousemoved(event) {
var f = document.querySelector('#floater');
console.log(event);
f.style.top = event.pageY + f.scrollTop + 'px';
f.style.left = event.pageX + 'px';
}
document.querySelector('#container').addEventListener('mousemove', mousemoved);
#container {
overflow: scroll;
position: relative;
}
#content {
height: 4000px;
background: lightblue;
}
#floater {
position: absolute;
border: 1px solid black;
padding: 1em 2em;
}
<div id="container">
<div id="floater">Hi</div>
<div id="content">content just to make the container taller</div>
</div>
I have solved this problem use another way.
in X axis we can do like this.
content means your main program width,codes adapted all resolution.
var widthContent = jQuery("#content").width();
jQuery("#floatTip").css("left", _xx - (window.screen.width - widthContent)/2 + "px");

Categories