Division of text follow the cursor via Javascript/Jquery - javascript

I wanted have a dynamic division of content follow you with the cursor in the web browser space.
I am not a pro at JS so I spent 2 hours to finally debugged a very stupid way to accomplish this.
$(document).ready(function () {
function func(evt) {
var evt = (evt) ? evt : event;
var div = document.createElement('div');
div.style.position = "absolute";
div.style.left = evt.clientX + "px";
div.style.top = evt.clientY + "px";
$(div).attr("id", "current")
div.innerHTML = "CURSOR FOLLOW TEXT";
$(this).append($(div));
$(this).unbind()
$(this).bind('mousemove', function () {
$('div').remove("#current");
});
$(this).bind('mousemove', func);
}
$("body").bind('mousemove', func)
});
As you can see this is pretty much Brute force and it slows down the browser quite a bit. I often experience a lag on the browser as a drag my mouse from one place to another.
Is there a way to accomplish this easier and faster and more intuitive.
I know you can use the cursor image technique but thats something I'm looking to avoid.
Thanks in advance.

Based on answer by Alconja, this might work better:
$(document).ready(function () {
//create the div
var div = $("<div/>",{
'css': {
"position": "fixed"
},
'text': "CURSOR FOLLOW TEXT"
}).appendTo("body");
//attach the mousemove event
$(window).bind('mousemove mouseover', function(evt) {
div.offset({left:evt.pageX, top: evt.pageY});
});
});

The performance issue comes from the fact that you're creating/destroying the div every time the mousemove event fires (and also binding/unbinding the event). You can simplify it greatly by creating the div once, attaching it to the document and then just moving it on the mousemove event like follows:
$(document).ready(function () {
//create the div
var div = $("<div></div>").css("position", "absolute").text("CURSOR FOLLOW TEXT").appendTo("body");
//attach the mousemove event
$("body").bind('mousemove', function(evt) {
div.css({
"left": evt.pageX + "px",
"top": evt.pageY + "px"
});
});
});

Related

Drag/Reposition Element On touchmove not working

I have a fixed window on my screen that I would like the user to be able to drag around the screen. While I have set this up to work for mouse inputs, I am having more difficulty getting this to work for touch screens.
So I have a basic box like so:
<div id="smallavatar" class="smallbox">
</div>
Which is then immediately followed by this JS (note that the first half is for the click events)
var divOverlay = document.getElementById ("smallavatar");
var isDown = false;
divOverlay.addEventListener('mousedown', function(e) {
isDown = true;
}, true);
document.addEventListener('mouseup', function() {
isDown = false;
}, true);
document.addEventListener('mousemove', function(event) {
event.preventDefault();
if (isDown) {
var deltaX = event.movementX;
var deltaY = event.movementY;
var rect = divOverlay.getBoundingClientRect();
divOverlay.style.left = rect.x + deltaX + 'px';
divOverlay.style.top = rect.y + deltaY + 'px';
}
}, true);
divOverlay.addEventListener('touchstart', e => {
clientX = e.touches[0].screenX;
clientY = e.touches[0].screenY;
});
divOverlay.addEventListener('touchmove', e => {
let x = divOverlay.style.left;
let y = divOverlay.style.top;
// Compute the change in X and Y coordinates.
// The first touch point in the changedTouches
// list is the touch point that was just removed from the surface.
deltaX = e.changedTouches[0].clientX - clientX;
deltaY = e.changedTouches[0].clientY - clientY;
divOverlay.style.left = divOverlay.style.left + deltaX;
divOverlay.style.top = divOverlay.style.top + deltaY;
});
Finally the following CSS is being used:
.smallbox{position:fixed; bottom:70px; right:0; width:360px; height:400px; z-index:20;}
Now while the touchmove event does work, the problem is that the box seems to fly off the screen very quickly. The idea is supposed to be that I'm trying to get the position the div was using before the touch event started, then work out how much movement has occured in the touchmove event and then from that update the left and top values with the new position it should be in.
Is there anything wrong that would explain why this isn't working as expected?
You have one major flaw in your code that causes the unexpected result:
At touchstart you store clientX and clientY, and than during touchmove you keep referencing those two values at deltaX = e.changedTouches[0].clientX - clientX; (and Y).
But while e.changedTouches[0].clientX keeps updating, clientX never gets updated and always keeps its initial start-value.
So for the next frame/iteration, deltaX = e.changedTouches[0].clientX - clientX; will actually be the delta-x of that last frame, plus the delta-x of the frame before, and the one before, and before, and so on till the very first frame.
So your divOverlay will be moving exponentially, and be out of sight in a fraction of a sec.
What the best choice is for getting the current position of divOverlay, depends a little on your situation, although I think in most cases, using pageX/pageY is probably your safest bet.
The other options are clientX/clientY and screenX/screenY, see this and this article for the differences between the three.
In any case, I wouldn't recommend using them interchangeably during one calculation, unless it's absolutely necessary.
See the live snippet below for the solution:
var divOverlay = document.getElementById("smallavatar");
/*MOUSE-LISTENERS---------------------------------------------*/
var isDown=false;
divOverlay.addEventListener('mousedown',function(){isDown=true;},true);
document.addEventListener('mouseup',function(){isDown=false;},true);
document.addEventListener('mousemove',function(e) {
e.preventDefault();
if (isDown) {
divOverlay.style.left = divOverlay.offsetLeft + e.movementX + 'px';
divOverlay.style.top = divOverlay.offsetTop + e.movementY + 'px';
}
},true);
/*TOUCH-LISTENERS---------------------------------------------*/
var startX=0, startY=0;
divOverlay.addEventListener('touchstart',function(e) {
startX = e.changedTouches[0].pageX;
startY = e.changedTouches[0].pageY;
});
divOverlay.addEventListener('touchmove',function(e) {
e.preventDefault();
var deltaX = e.changedTouches[0].pageX - startX;
var deltaY = e.changedTouches[0].pageY - startY;
divOverlay.style.left = divOverlay.offsetLeft + deltaX + 'px';
divOverlay.style.top = divOverlay.offsetTop + deltaY + 'px';
//reset start-position for next frame/iteration
startX = e.changedTouches[0].pageX;
startY = e.changedTouches[0].pageY;
});
.smallbox{position:fixed; bottom:70px; right:0; width:36px; height:40px; z-index:20; background:red;}
<div id="smallavatar" class="smallbox"></div>
jsfiddle: https://jsfiddle.net/2hdczkwn/4/
To address your major flaw, I added startX = e.changedTouches[0].pageX; and startY = e.changedTouches[0].pageY; to the end of your touchmove listener, resetting the start-position for each new frame/iteration to the end-position of the last frame/iteration.
I also added e.preventDefault(); to your touchmove listener, because otherwise any scrollable page would also start scrolling while you were dragging the divOverlay.
I converted your arrow functions into traditional ones, like your mouse listeners.
I added var startX=0, startY=0; outside the functions to make sure they are global vars.
I replaced var rect = divOverlay.getBoundingClientRect(); and rect.x and rect.y inside your mousemove listener, and divOverlay.style.left and divOverlay.style.top inside your touchmove listener, with divOverlay.offsetLeft and divOverlay.offsetTop.
This is actually quite important, since divOverlay.style.left returns a px value, e.g. 57px. When this value is used in a calculation, like 57px + 12, it will not result in 69 or 69px but instead in NaN.
I can't help but notice that your mouse and touch listeners are written in a different coding style, mouse uses traditional JS, while touch is written in the new ES6, using let and arrow functions.
As if you copied the touch listeners from someone else and didn't change it to match the rest of your code.
While it is fine to use either style and to use other people's code (as long as you have permission), I would discourage using them both in the same project, and it is never a good idea to simply copy someone else's code without rewriting it to fit your own style.
This will make sure your whole project retains its current style of coding, and has the added advantage of you actually understanding the code you're using.

sublime-scroll plugin is not scrolling as expected (iframe event catching issue)

I want to read mouse position from an iframe. I am doing it with this implementation:
$($("#sublime-scroll-iframe").contents()[0], window).find('body').bind("mousedown",
function(e) {
console.log("x:" + (e.pageX) + ", y:" + e.pageY);
}
);
My working example: http://jsfiddle.net/s37e1ro0/1/ but
I can't make it to work with demux's sublime-scroll js script. Output is window coordinates or nothing.
Sublime-scroll example: http://django.is/ or you can download example files from https://github.com/demux/sublime-scroll
The reason is, demux's script actually doesn't work completely as Sublime scroll. For example. In sublime, you see part of code, and you click on that part, sublime scrolls to that part code. That isn't the situation with demux's script. Clicking on part of page doesn't scroll to that part of the page. It scrolls to position of ratio between window and whole document.
I couldn't find a reason why it's not working. Does anyone have any idea?
Or if anyone have an idea to do it without mouse coordinates?
$(document).ready(function() {
$.sublimeScroll({
top: 60, // px to top
bottom: 40, // px to bottom
scrollWidth: 200, // Width of scrollbar
removeElements: 'script',
fixedElements: 'header.top, footer.bottom',
contentWidth: 860, // Scroll viewport width
minWidth: 800 // Min width of window to display scroll
});
$("#sublime-scroll-overlay").css('display', 'none');
var sscIfBody = $($("#sublime-scroll-iframe").contents()[0], window).find('body');
var sscIfBar = $("#sublime-scroll-bar", sscIfBody);
var sHold = false;
var sDeltaY = 0;
sscIfBody.bind("mousedown", function(e) {
window.scrollTo(e.pageX, e.pageY - window.innerHeight / 2);
e.preventDefault();
});
sscIfBar.bind('mousedown', function(e) {
sDeltaY = e.offsetY === undefined ? e.originalEvent.layerY : e.offsetY;
sHold = true;
e.stopPropagation();
e.preventDefault();
});
sscIfBody.bind("mouseup", function(e) {
sHold = false;
});
sscIfBody.bind("mousemove", function(e) {
if (sHold)
window.scrollTo(e.pageX, e.pageY - sDeltaY);
});
});
That's it. Now it's working same as Sublime's scroll. Enjoy!

HTML5 draggable's drop event not getting triggered intermittently due to DOM manipulation in dragover event

I am using html5 'draggable' attribute to drag 2 elements within a container and svg line to connect the two.
Once connected, Dragging the first Div should redraw the connecting svg line (i do on dragover event by calling 'handleDragOver' function). But If you drag the first div faster, drop event is not triggered and the div maintains it's original place while the line gets drawn.
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault();
}
//Some code doing DOM computation and manipulation
}
return false;
//e.dataTransfer.dropEffect = 'move';
}
How can I ensure that drop event gets triggered every time.
Please note:
I can't use any framework, just plain javascript
I can't not redraw line while dragging.
drag functionality works fine when I'm not doing any computation/redrawing in 'handleDragOver'
Here is the code: http://jsfiddle.net/bhuwanbhasker/3yx9ds4m/1/
Please take a look on the updated fiddle: http://jsfiddle.net/sejoker/d4vs9fgs/1/
following changes:
line manipulation moved from dragover's handler to handleDrop, redraw line once during drag'n'drop operation
calling moveLine in setTimeout seems to improve usability (optional)
minor changes in moveLine function to connect draggable elements properly (optional)
function handleDrop(e) {
console.log('enter Drop');
if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}
var offset = e.dataTransfer.getData('Text').split(',');
dragSrcEl.style.left = (e.clientX + parseInt(offset[0], 10)) + 'px';
dragSrcEl.style.top = (e.clientY + parseInt(offset[1], 10)) + 'px';
setTimeout(function(){
var elem = svgLine.aLine;
if (elem !== null) {
var x = e.clientX - svgLine.left,
y = e.clientY - svgLine.top;
moveLine(x, y, elem, offset[2]);
}
}, 50)

Jquery Drag and Drop without plugins

I have tried to create a drag and drop plugin using JQuery.
$('.draggable').on{
mousemove : function(){
var mouseposition = { // this also needs to account for onclick offset of pointer vis-a-vis element
x : pageX,
y : pageY
};
$(this).css({
top : mouseposition.y,
left : mouseposition.y
});
if( // this statement is kinda bogus, idea is to perform a collision detection via coordinate comparison
$('.draggable').offset().top < $(.droppable').offset().top
&&
$('.draggable').offset().left < $(.droppable').offset().left
) {
alert('the item has been dropped');
}
}
});
Here is the demo link what I have tried.
I have reworked your code, and updated the fiddle.
http://jsfiddle.net/XTMK8/2/
var dragging = undefined;
$('.draggable').on('mousedown', function(){
dragging = $(this);
});
$('body').on('mousemove', function(e){
if(typeof dragging != "undefined") {
dragging.css({
top : e.pageY - 50,
left : e.pageX - 50
});
}
});
$('body').on('mouseup', function(){
dragging = undefined;
});
Collision Detection
I would then recommend using the following snippet to handle collision:
jQuery/JavaScript collision detection
I'm assuming this must be an academic task or you want to do it for learning purposes (otherwise, why someone wouldn't want to use JQuery UI's draggable?) but anyway, the link below should guide in the right direction: http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/
If you still want to know what's wrong with your code, I recommend starting over and add bit by bit to try to achieve the basic functionalities before coming up with a draggable and droppable at once, e.g., your mousemove function seems different from the one in JQuery's doc, I believe that, in order to retrieve pageX and pageY, you need the event object within the function's parameters:
$("#target").mousemove(function(event) {
var msg = "Handler for .mousemove() called at ";
msg += event.pageX + ", " + event.pageY;
$("#log").append("<div>" + msg + "</div>");
});
Try to set some breakpoints using Firebug and see if all variables are being populated accordingly.
I hope that helps, cheers!

jQuery - how to resize image on mousemove in Chrome?

I've put together a small script (JavaScript - jQuery) for testing an image resize operation that is dependent on the mousemove event. In short, the idea is to click on the image once and then drag the cursor around. The image resizes at every mouse move, its bottom-right corner "following" your cursor around.
The problem I've encountered is this: right after you start moving the cursor around, the resize works a bit jerky. After 1-2 seconds, it runs very smoothly. The same situation occurs if you stop moving the cursor around for a bit and then move it again.
This issue appears to happen only in Google Chrome, so my first thought is that it has something to do with this browser's anti-aliasing feature. But I'm not an expert.
The image is quite big (width&height - wise, not "KB"-wise)
You can test this "mini-app" here: http://picselbocs.com/projects/helsinki-map-application/test.php
And bellow is the code:
<img src="Helsinki.jpg" id="map" style="width: 526px; height:300px; position: absolute; top:0; left:0" />
<script>
var drag = false;
(function(){
$('#map').on('click',function(){
drag = true;
});
$(document).on('mousemove',function(e){
if (drag)
$('#map').css({ 'height': e.pageY, 'width': e.pageX });
});
})();
</script>
If anyone can provide a solution to this problem I would greatly appreciate it.
http://asp-net-by-parijat.blogspot.in/2014/09/aspnet-image-magnifying-effect-with.html
!function ($) {
"use strict";
var Magnify = function (element, options) {
this.init('magnify', element, options)
}
Magnify.prototype = {
constructor: Magnify
, init: function (type, element, options) {
var event = 'mousemove'
, eventOut = 'mouseleave';
this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
this.nativeWidth = 0
this.nativeHeight = 0
if(!this.$element.parent().hasClass('magnify')) {
this.$element.wrap('<div class="magnify" \>');
this.$element.parent('.magnify').append('<div class="magnify-large" \>');
}
this.$element.siblings(".magnify-large").css("background","url('" + this.$element.attr("src") + "') no-repeat");
this.$element.parent('.magnify').on(event + '.' + this.type, $.proxy(this.check, this));
this.$element.parent('.magnify').on(eventOut + '.' + this.type, $.proxy(this.check, this));
}

Categories