I am trying to incrementally reposition an element by setting the -webkit-transform property to +=200px
But it doesn't work. I'm missing something, but don't know what.
http://jsfiddle.net/yVSDC/
Clicking the div is supposed to move it further down by 200px everytime.
CSS doesn't work like that, and jQuery doesn't pull that data out so you can do it like that.
You'd need to read the value, add 200 and then reset it.
var getTranslatedY = function (element) {
var transform = element.css("transform") || element.css("-webkit-transform") || element.css("-moz-transform");
if (transform == "none") {
return 0;
}
return parseInt((transform.match(/^matrix\(.*?(-?[\d.]+)\)$/) || [])[1]) || 0;
};
$('#m').on(
'click',
function () {
var element = $(this);
element
.css('-webkit-transform',
"translateY(" + (getTranslatedY(element) + 200) + "px)");
});
jsFiddle.
var step = 200;
$('body').on('click', "#m", function(){
$(this).css('-webkit-transform','translateY('+ step +'px)');
step = step+200;
});
And instead -webkit-transform:translateY(100px); in CSS you can set margin-top: 100px;
http://jsfiddle.net/yVSDC/28/
You have to get the Current webkit-transform value and increment it. Alternative Solution is ustin the top CSS Property
You can try this (it's free): http://ricostacruz.com/jquery.transit/
Sample Code:
$('.box').transition({ x: '200px' });
$('.box').transition({ y: '200px' });
$('.box').transition({ x: '200px', y: '200px' });
Related
//First function -> Makes a heading float when scrolled past it
if (window.matchMedia('(min-width: 767px)').matches) {
$(function(){
var topBlockheight=$('.site-header').height();
// Check the initial Position of the fixed_nav_container
var stickyHeaderTop = $('.float-h2').offset().top;
var stopFloat = $('#stop-float').offset().top;
$(window).scroll(function(){
if( ( $(window).scrollTop() > stickyHeaderTop-topBlockheight && $(window).scrollTop() < stopFloat-topBlockheight )) {
$('.float-h2').css({position: 'fixed', top: '200px'});
}
else {
$('.float-h2').css({position: 'relative', top: '0px'});
}
});
});
}
// Adds Hover effect for boxes
if (window.matchMedia('(min-width: 767px)').matches) {
$(document).ready(function(){
$(".thumb-cta").mouseover(function(){
max_value=4;
random_value= Math.floor((Math.random() * max_value) + 1);
$(this).attr("data-random",random_value);
});
})
}
These are my two only functions in jQuery from my site which i decided to try to rewrite in vanilla JS. The reason for this decision is because I dont want a 90kb file (jquery main file) to be loaded for 2 basic functions (basic but still can't do them, yes I know).
I've tryed to re write them using http://youmightnotneedjquery.com and https://www.workversatile.com/jquery-to-javascript-converter and i ended up with this code, which does not have any errors in the console, but still does not work :((
let el = document.getElementById("masthead");
let topBlockheight = parseFloat(getComputedStyle(el, null).height.replace("px", ""))
var rect = document.getElementById("float-h2").getBoundingClientRect();
var offset = {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX,
};
var brect = document.getElementById("stop-float").getBoundingClientRect();
var boffset = {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX,
};
window.scroll(function(){
if( ( window.scrollTop() > rect-topBlockheight && window.scrollTop() < stopFloat-topBlockheight )) {
document.getElementById("float-h2").css({position: 'fixed', top: '200px'});
}
else {
document.getElementById("float-h2").css({position: 'relative', top: '0px'});
}
});
Any ideas how I can move on, because I'm really stuck
hope this work for you
if (window.matchMedia('(min-width: 767px)').matches) {
//Note: if "site-header" is more than one element remove [0] and create a loop
var topBlockheight=document.getElementsByClassName('site-header')[0].offsetHeight
var stickyHeaderTop = document.getElementsByClassName('float-h2')[0].offsetTop;
var stopFloat = document.getElementById('stop-float').offsetTop;
window.addEventListener("scroll", function(){
if( ( window.scrollY > stickyHeaderTop-topBlockheight && window.scrollY < stopFloat-topBlockheight )) {
document.getElementsByClassName('float-h2')[0].style.position = 'fixed'
document.getElementsByClassName('float-h2')[0].style.top = '200px'
}
else {
document.getElementsByClassName('float-h2')[0].style.position = 'relative'
document.getElementsByClassName('float-h2')[0].style.top = 0
}
});
}
// Adds Hover effect for boxes
if (window.matchMedia('(min-width: 767px)').matches) {
document.onreadystatechange = function(){
if(document.readyState === "interactive") {
document.getElementsByClassName('thumb-cta')[0].addEventListener("mouseover", function(){
max_value=4;
random_value= Math.floor((Math.random() * max_value) + 1);
this.setAttribute("data-random",random_value);
});
}
}
}
Details
jQuery
in jQuery to select elements by className or tagName it's enough to write $('.element') or $('tag') but in Vanillajs to select elements you can use document.getElementsByClassName('elements') or document.getElementsByTagName('elements') which return found elements sharing the same className or tagName in an array if you want to select only one element you can write the element index like document.getElementsByClassName('elements')[0] but if you want to select all elements you will be need to create a loop
var el = document.getElementsByClassName('elements')
for(var i = 0; i < el.length; i++) {
el[i].style.padding = '25px';
el[i].style.background = 'red';
}
and because of id is unque name for the element you don't need to any extra steps you can select it diectly select it like document.getElementById('id')
that was about selecting elements
height() method which uses get the element height - in Vanillajs js to get the element height you can use offsetHeight property or getComputedStyle(element, pseudo|null).cssProp
Example
element.offsetHeight, parseInt(getComputedStyle(element, null).height)
offset() method which uses to return coordinates of the element this method have 2 properties top, left in Vanillajs to get the element offset top you can use offsetTop propery directly like element.offsetTop
jQuery provides a prototype method like css() which provide an easy and readable way to styling elements like in normal object propery: value - in Vanillajs to styling elements you will be need to use style object like element.style.prop = 'value' and you will be need to repeat this line every time you add new css property like
el.style.padding = '25px';
el.style.background = 'red';
//and they will repeated as long as you add new property
if you don't want to include jQuery into your project and need to use this method you can define it as prototype method for HTMLElement, HTMLMediaElement
Example 1: for styling one element
//for html elements
HTMLElement.prototype.css = function(obj) {
for(i in obj) {
this.style[i] = obj[i]
}
}
//for media elements like video, audio
HTMLMediaElement.prototype.css = function(obj) {
for(i in obj) {
this.style[i] = obj[i]
}
}
//Usage
var el = document.getElementsByClassName('elements')[0]
el.css({
'padding': '25px',
'background-color':
})
if you wants to add this style for multiple elements you can define it as prototype method for Array
Example 2: for multiple elements
Array.prototype.css = function(obj) {
for(i = 0; i < this.length; i++) {
if (this[i] instanceof HTMLElement) {
for(r in obj) {
this[i].style[r] = obj[r]
}
}
}
}
//Usage
var el1 = document.getElementsByClassName('elements')[0]
var el2 = document.getElementsByClassName('elements')[1]
[el1, el2].css({
'background-color': 'red',
padding: '25px'
})
jQuery allow you to add events directly when selecting element like $('.element').click(callback) but in Vanillajs you can add events with addEventListener() or onevent proprty like document.getElementById('id').addEventListener('click', callback) , document.getElementById('id').onclick = callback
$(document).ready(callback) this method uses to make your code start working after loading the libraries, other things it's useful to give the lib enough time to loaded to avoid errors - in Vanilla js you can use onreadystatechange event and document.readyState protpety which have 3 values loading, interactive, complete
Example
document.onreadystatechange = function () {
if (document.readyState === 'interactive') {
//your code here
}
}
Your Coverted Code
at this line parseFloat(getComputedStyle(el, null).height.replace("px", "")) you don't need to replace any thing because parseInt(), parseFloat will ignore it
element.css() id don't know how you don't get any errors in the console when this method is undefined you will be need to define it as above to make it work
scroll event is not defined you will be need to use window.onscroll = callback like example above
i got this strange behaviour
when i do a slow hover on image everything is working, the image grows and on hover out the image shrinks.
But when i repeat the hover fast the image keeps growing and growing and the position is changing according to the hover speed
Please see fiddle
Jquery
$(document).ready(function () {
var cont_left = $("#container").position().left;
$("a img").hover(function () {
// hover in
$(this).parent().parent().css("z-index", 1);
current_h = $(this, 'img')[0].height;
current_w = $(this, 'img')[0].width;
$(this).stop(true, false).animate({
width: (current_w * 1.3),
height: (current_h * 1.3),
left: "-=50",
top: "-=50"
}, 300);
}, function () {
// hover out
$(this).parent().parent().css("z-index", 0);
$(this).stop(true, false).animate({
width: current_w + 'px',
height: current_h + 'px',
left: "+=50",
top: "+=50"
}, 300);
});
$(".img").each(function (index) {
var left = (index * 160) + cont_left;
$(this).css("left", left + "px");
});
});
Please advise how to i fix the image grow and position.
P.S: every image has a different dimentions
These lines are the key to the problem:
current_h = $(this, 'img')[0].height;
current_w = $(this, 'img')[0].width;
When you .stop the image-growing animation, it doesn't shrink back to its original size (unless you set its second param to true - but you assign false to it explicitly, and I assume you know what you're doing here). So both dimensions are set to the increased value actually.
Solution is simple: always use the original size of the images:
$(document).ready(function () {
var current_h, current_w;
// ...
current_h = current_h || $(this, 'img')[0].height;
current_w = current_w || $(this, 'img')[0].width;
JS Fiddle.
Two sidenotes here. First, there's a similar problem with positioning of these elements: move too fast, and your images will shift to the left-upper or right-lower corners (depending on the phase); that's because, again, animation is done against the current state of things, which is not the same as original when the previous animation is stopped with .stop(true, false).
Second, using $(this, 'img')[0] in this case is essentially the same as just this. Remember, in event handlers this corresponds to the DOM element having this event handler assigned.
So this is how it can be done (demo):
$("a img").hover(function() {
var $this = $(this);
$this.closest('.img').css('z-index', 1);
var orig = $this.data('orig');
if (!orig) { // caching the original sizes via `jQuery.data`
orig = {
width: this.width,
height: this.height
};
$this.data('orig', orig);
}
$this.stop(true, false).animate({
width: orig.width * 1.3,
height: orig.height * 1.3,
left: -(orig.width * 0.3 / 2),
top: -(orig.height * 0.3 / 2)
}, 300);
}, function () {
var $this = $(this),
orig = $this.data('orig');
if (!orig) {
return false;
// actually, it should never be here,
// as calling 'mouseleave' without data precached
// means 'mouseenter' has been never called
}
$this.closest('.img').css('z-index', 0);
$this.stop(true, false).animate({
width: orig.width,
height: orig.height,
left: 0,
top: 0
}, 300);
});
The problem is that when you hover quickly, your values current_h and current_w don't measure the original height and width, but the current height and width. Thus, every time, you're increasing the value.
Solution
I've used a simple .each() function here to set the original height and width of each image as data attributes which can then be accessed when you're setting current_h and current_w.
$('img').each(function(i, el) {
$(el).attr({
"data-original-width": $(this).width(),
"data-original-height": $(this).height()
});
});
current_h = $(this).attr("data-original-height");
current_w = $(this).attr("data-original-width");
WORKING FIDDLE
You don't have to use the each function though. If you know the height and width of the images before rendering, then you can set these as data attributes in your HTML
I want to be able to drag a group of elements with jQuery, like if I selected and dragged multiple icons on the Windows desktop.
I found the demo of threedubmedia's jQuery.event.drag:
http://threedubmedia.com/code/event/drag/demo/multi
http://threedubmedia.com/code/event/drag#demos
I think this plugin is great. Is this good and popular library? Do you know websites or applications which use it?
Are there any other libraries or plugins to drag multiple objects?
Can jQuery UI drag multiple objects?
var selectedObjs;
var draggableOptions = {
start: function(event, ui) {
//get all selected...
selectedObjs = $('div.selected').filter('[id!='+$(this).attr('id')+']');
},
drag: function(event, ui) {
var currentLoc = $(this).position();
var orig = ui.originalPosition;
var offsetLeft = currentLoc.left-orig.left;
var offsetTop = currentLoc.top-orig.top;
moveSelected(offsetLeft, offsetTop);
}
};
$(document).ready(function() {
$('#dragOne, #dragTwo').draggable(draggableOptions);
});
function moveSelected(ol, ot){
console.log(selectedObjs.length);
selectedObjs.each(function(){
$this =$(this);
var pos = $this.position();
var l = $this.context.clientLeft;
var t = $this.context.clientTop;
$this.css('left', l+ol);
$this.css('top', t+ot);
})
}
I am the author of the of the threedubmedia plugins. I added this functionality for supporting multiple elements, because I could not find a satisfactory solution anywhere else.
If you need a solution that works with the jQuery UI, here is a plugin which adds some multi-drag functionality, though the demos don't seem to work correctly in Firefox for Mac.
http://www.myphpetc.com/2009/11/jquery-ui-multiple-draggable-plugin.html
This worked for me.
Fiddle here:
var selectedObjs;
var draggableOptions = {
start: function(event, ui) {
//get all selected...
if (ui.helper.hasClass('selected')) selectedObjs = $('div.selected');
else {
selectedObjs = $(ui.helper);
$('div.selected').removeClass('selected')
}
},
drag: function(event, ui) {
var currentLoc = $(this).position();
var prevLoc = $(this).data('prevLoc');
if (!prevLoc) {
prevLoc = ui.originalPosition;
}
var offsetLeft = currentLoc.left-prevLoc.left;
var offsetTop = currentLoc.top-prevLoc.top;
moveSelected(offsetLeft, offsetTop);
selectedObjs.each(function () {
$(this).removeData('prevLoc');
});
$(this).data('prevLoc', currentLoc);
}
};
$('.drag').draggable(draggableOptions).click(function() {$(this).toggleClass('selected')});
function moveSelected(ol, ot){
console.log("moving to: " + ol + ":" + ot);
selectedObjs.each(function(){
$this =$(this);
var p = $this.position();
var l = p.left;
var t = p.top;
console.log({id: $this.attr('id'), l: l, t: t});
$this.css('left', l+ol);
$this.css('top', t+ot);
})
}
Thanks to ChrisThompson and green for the almost-perfect solution.
I wanted to add (this coming up high in google), since none of the plugins in this thread worked and it is not nativity supported by jquery ui, a simple elegant solution.
Wrap the draggable elements in a container and use an event to drag them all at once, this allows for singles draggables and multidraggables (but not really selective draggables).
jQuery(document).click(function(e) {
if(e.shiftKey) {
jQuery('#parent-container').draggable();
}
});
Check this out:
https://github.com/someshwara/MultiDraggable
Usage:$(".className").multiDraggable({ group: $(".className")});
Drags the group of elements together. Group can also be an array specifying individual elements.
Like:$("#drag1").multiDraggable({ group: [$("#drag1"),$("#drag2") ]});
Put your items into some container and make this container draggable. You will need to set handle option to be a class of your item element. Also you will need to recalculate items position after drag. And obviously when you deselect items you have to take them from this container and put back to their origin.
This is what i used, Worked in my case.
function selectable(){
$('#selectable').selectable({
stop: function() {
$('.ui-selectee', this).each(function(){
if ($('.ui-selectee').parent().is( 'div' ) ) {
$('.ui-selectee li').unwrap('<div />');
}
});
$('.ui-selected').wrapAll('<div class=\"draggable\" />');
$('.draggable').draggable({ revert : true });
}
});
};
there is Draggable in the jquery UI
all you would have to do is:
$(selector).draggable(); // and you are done!
see example here: http://jsfiddle.net/maniator/zVZFq/
If you really want multidragging you can try using some click events to hold the blocks in place
$('.drag').draggable();
$('.drag').click(function(){
console.log(this, 'clicked')
var data = $(this).data('clicked');
var all = $('.all');
if(data == undefined || data == false){
$(this).data('clicked', true);
this.style.background = 'red';
$(this).draggable('disable');
if(all.children().length <= 0){
all.draggable().css({
top: '0px',
left: '0px',
width: $(window).width(),
height: $(window).height(),
'z-index': 1
});
}
var top = parseInt(all.css('top').replace('px','')) +
parseInt($(this).css('top').replace('px',''))
var left = parseInt(all.css('left').replace('px','')) +
parseInt($(this).css('left').replace('px',''))
$(this).css({
top: top,
left: left
})
$('.all').append($(this));
}
else {
$(this).data('clicked', false);
this.style.background = 'grey';
$(this).draggable('enable');
$('body').append($(this));
if(all.children() <= 0){
all.draggable('destroy');
}
/*
var top = parseInt(all.css('top').replace('px','')) -
parseInt($(this).css('top').replace('px',''))
var left = parseInt(all.css('left').replace('px','')) -
parseInt($(this).css('left').replace('px',''))
$(this).css({
top: top,
left: left
})*/
}
})
See example here: http://jsfiddle.net/maniator/zVZFq/5
Is there a simple way to locate all DOM elements that "cover" (that is, have within its boundaries) a pixel with X/Y coordinate pair?
You can have a look at document.elementFromPoint though I don't know which browsers support it.
Firefox and Chrome do. It is also in the MSDN, but I am not so familiar with this documentation so I don't know in which IE version it is included.
Update:
To find all elements that are somehow at this position, you could make the assumption that also all elements of the parent are at this position. Of course this does not work with absolute positioned elements.
elementFromPoint will only give you the most front element. To really find the others you would have to set the display of the front most element to none and then run the function again. But the user would probably notice this. You'd have to try.
I couldn't stop myself to jump on Felix Kling's answer:
var $info = $('<div>', {
css: {
position: 'fixed',
top: '0px',
left: '0px',
opacity: 0.77,
width: '200px',
height: '200px',
backgroundColor: '#B4DA55',
border: '2px solid black'
}
}).prependTo(document.body);
$(window).bind('mousemove', function(e) {
var ele = document.elementFromPoint(e.pageX, e.pageY);
ele && $info.html('NodeType: ' + ele.nodeType + '<br>nodeName: ' + ele.nodeName + '<br>Content: ' + ele.textContent.slice(0,20));
});
updated: background-color !
This does the job (fiddle):
$(document).click(function(e) {
var hitElements = getHitElements(e);
});
var getHitElements = function(e) {
var x = e.pageX;
var y = e.pageY;
var hitElements = [];
$(':visible').each(function() {
var offset = $(this).offset();
if (offset.left < x && (offset.left + $(this).outerWidth() > x) && (offset.top < y && (offset.top + $(this).outerHeight() > y))) {
hitElements.push($(this));
}
});
return hitElements;
}
When using :visible, you should be aware of this:
Elements with visibility: hidden or opacity: 0 are considered visible,
since they still consume space in the layout. During animations that
hide an element, the element is considered to be visible until the end
of the animation. During animations to show an element, the element is
considered to be visible at the start at the animation.
So, based on your need, you would want to exclude the visibility:hidden and opacity:0 elements.
I am having problem getting my tooltip to work when using the jQuery load() function. The tooltip works fine if i don't use load() to load external dynamic data.
I googled and found the i may need to use live(), but I can't figure how to get it to work. Any suggestion?
thank you!!
Here is my scripts:
function loadEMERContent(uid) {
$("#ActionEWPNBook").load("ajaxLoadDATA.cfm?uid="+uid, null, showLoading);
$("#EWPNBookloading").html('<img src="/masterIncludes/images/ajaxLoading.gif" alt="loading" align="center" />');
}
function showLoading() {
$("#EWPNBookloading").html('');
}
function simple_tooltip(target_items, name){
$(target_items).each(function(i){
$("body").append("<div class='"+name+"' id='"+name+i+"'><p style='padding:5px;'>"+$(this).attr('title')+"</p></div>");
var my_tooltip = $("#"+name+i);
$(this).removeAttr("title").mouseover(function(){
my_tooltip.css({opacity:0.8, display:"none"}).stop().fadeIn(400);
}).mousemove(function(kmouse){
my_tooltip.css({left:kmouse.pageX+15, top:kmouse.pageY+15});
}).mouseout(function(){
my_tooltip.stop().fadeOut(400);
});
});
}
Here is my ajaxLoadDATA.cfm: it returns an unorder list
<li><span title="dynamic title here" class="tipthis">date</span></li>
In your callback function, you need to run the tooltip code against the new items, like this:
function showLoading(data) { //data = the response text, passed from `.load()`
$("#EWPNBookloading").html('');
var items = //get items here, something like $('.giveMeATooltip', data);
var name = //set name, not sure what you're using for this
simple_tooltip(items, name);
}
One side tip, if you change this line:
$("body").append("<div class='"+name+"' id='"+name+i+"'><p style='padding:5px;'>"+$(this).attr('title')+"</p></div>");
To something like this:
$("body").append(
$("<div></div>", { 'class': name, 'id': name + i }).append(
$("<p style='padding:5px;'></p>").text($(this).attr('title'))
)
);
Your tooltip generation will be much faster due to how jQuery can cache document fragments for reuse.
I use a modified version of this tooltip. This version uses .live so loaded content will automatically have tooltip functionality. All you need to do is:
Add this script to your main page (adding it as an external file is perferred)
You need to ensure that the elements that need a tooltip have a class="tipthis" and that the tooltip contents are within the title attribute. Also, the tooltip can contain HTML (e.g. <h1>Tooltip</h1>Hello,<br>World).
You will also need some basic CSS:
#tooltip { background: #f7f5d1; color: #333; padding: 5px; width: 300px; }
Here is the script (using live and it requires jQuery version 1.4+)
/* Tooltip script */
this.tooltip = function(){
// Defaults
var tooltipSpeed = 300; // fadein speed in milliseconds
var xOffset = 20; // Don't use negative values here
var yOffset = 20;
$('.tipthis').live('mouseover',function(e) {
this.t = this.title;
this.title = '';
$('<div></div>', {
id : 'tooltip',
css: {
display : 'none',
position: 'absolute',
zIndex : 1000,
top : (e.pageY - xOffset) + 'px',
left : (e.pageX + yOffset) + 'px'
}
})
.html( this.t )
.appendTo('body');
$('#tooltip').fadeIn(tooltipSpeed);
})
.live('mouseout',function(){
this.title = this.t;
$('#tooltip').remove();
})
.live('mousemove',function(e){
$("#tooltip").css({
top : (e.pageY - xOffset) + 'px',
left: (e.pageX + yOffset) + 'px'
});
})
}
$(document).ready(function(){ tooltip(); });
Here is some sample HTML:
Hover over me!