Collision detection between two squares in javascript - javascript

I've got a problem in my code, I can move the red one (square1) by clicking on it,what I want to do is to detect a collision when the red one touch the blue one. I want it to change colour when there is a collision...
Here is my code to be more clear:
http://jsbin.com/iFAlIyIv/4/edit

Your basic approach was right, the problems were things like this:
Instead of square1.left, you want square1.offsetLeft. Elements don't have a left property. Same goes for top, width, and height.
Instead of document.getElementById("square2"), you need to select the element by class name, since there's no element with that ID (only an element with that class).
You're calling changecouleur, but you probably meant to call colorswap. Looks like a bit of unfinished refactoring.
You also don't need any of the additional checks after this:
if (bl > ar || br < al) {
return false;
} //overlap not possible
if (bt > ab || bb < at) {
return false;
} //overlap not possible
If neither of these conditions are true, they must overlap.
http://jsbin.com/iFAlIyIv/13/edit

Related

JavaScript recognizes up arrow press when on first line of text area [duplicate]

Given a textarea with content that flows like this
––––––––––––––––––––––––––
| This is some text, which |
| wraps like this. |
––––––––––––––––––––––––––
How can one tell if the text-cursor is on the first line of the textarea?
Obviously, checking for a newline character (\n) works if one wants to see if the cursor appears before the first line break, but testing for a 'soft' line break seems more challenging.
Here is a sample jsFiddle to experiment with.
I have not yet come up with a strategy, but I suspect it may involve copying the text up until the cursor position into a cloned textarea (or div), and making the width as long as it needs to be so it doesn't wrap. If the cloned area has a width less than the original's width, then the cursor would seem to have to be on the first line. There may a simpler option, something more elegant, or (best of all) an existing and well-tested solution.
Target browsers are Webkit (Chrome/Safari) & Firefox. I.e. IE compatibility is not a concern at this time (if that makes any difference).
Thanks for reading.
EDIT: Seeking line number of text caret, not mouse cursor.
falsarella gave an excellent answer, that highlighted an ambiguity in the question. What I am seeking is whether the text cursor (“caret” may be a better word) is on the first line. I have updated the question and the jsFiddle to reflect.
I only know of one "working method". The method requires use of textarea's "cols" attribute. Long story short, set the cols to the width you want, then divide the cursor position and floor it to see if it is less than 1, thus it = line 1!
Might be easier to explain if I just show you a code example.
$("textarea").live("keyup", function(e) {
if ($("textarea").attr("cols")) {
var cols = parseInt($("textarea").attr("cols")),
curPos = $('textarea').prop("selectionStart"),
result = Math.floor(curPos/cols);
var msg = (result < 1) ? "Cursor is on the First line!" : "Cursor is on the line #"+(result+1);
console.log($("p").text(msg).text());
};
});​
however, this may still require some wired math as some col sizes may still say "line 2" when the cursor is simply at the END of line one (which technically would still be right since any character would drop to line 2)
jsFiddle
Having that 15 is the line height, this works (tested in firefox):
http://jsfiddle.net/h46jh/12/
$("textarea").click(function (evt) {
cursor_position = evt.pageY - $('textarea').offset().top;
if (cursor_position <= 15) {
alert("first line");
} else {
alert("other line");
}
});
Credits:
Find mouse position relative to element

Odd if-else behavior in Javascript

I'm trying to make a simple Javascript button to toggle a menu on and off the screen. I have a little if-else statement that detects the current position of the <nav> and changes it's left css property to that effect.
JSBin
Now, as you see in my code, this will show the menu once but won't hide it back afterwards:
if (navStyle == '0') { setNav('-500px'); }
else { setNav('0'); }
And this will do the job properly:
if (navStyle == '-500px') { setNav('0'); }
else { setNav('-500px'); }
Weird right? Anyone knows what's going on?
This is because the width will never actually be equal to 0, it will be something like 0px depending upon the units you choose. Your second set of conditions work because they check for the width first (500px) and if it doesn't match chooses the other (0px).
You can handle this in a variety of ways, including extracting just the number value from 0px, however since you already have this working, its just something to be aware of in the future. :)

change css on scroll event w/ requestAnimation Frame

I want to change the background color of in-viewport elements (using overflow: scroll)
So here was my first attempt:
http://jsfiddle.net/2YeZG/
As you see, there is a brief flicker of the previous color before the new color is painted. Others have had similar problems.
Following the HTML5 rocks instructions, I tried to introduce requestAnimationFrame to fix this problem to no avail:
http://jsfiddle.net/RETbF/
What am I doing wrong here?
Here is a simpler example showing the same problem: http://jsfiddle.net/HJ9ng/
Filed bug with Chromium here: http://code.google.com/p/chromium/issues/detail?id=151880
if it is only the background color, well why don't you just change the parent background color to red and once it scroll just change it to pink?
I change your CSS to that
#dad
{
overflow-y: scroll;
overflow-x: hidden;
width: 100px;
height: 600px;
background-color:red;
}​
I remove some of you Jquery and change it to this
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
});
And I remove this line
iChild.css('backgroundColor', 'red');
But is the Red color it is important that won't work for sure http://jsfiddle.net/2YeZG/5/
I like Manuel's Solution.
But even though I don't get what you're exactly trying to do, I want to point out a few things.
In your fiddle code, I saw that you included Paul Irish's Shim for requestAnimationFrame.
But you never use it.
(It's basically a reliable setTimeOut, nothing else) it's from frame based animations.)
So since you just want to change some CSS properties, I don't see why you would need it. Even if you want transitions, you should rely on CSS transitions.
Other than that your code could look something like
dad.bind('scroll', function() {
dad.css('background-color', 'pink');
eachElemNameHere.css('background-color','randomColor');
});
Also you should ideally not use something like that if you can help it. You should just add and remove class names and add all these properties in your CSS. Makes it work faster.
Also, again I don't quite get it, but you could use the jQuery function to find out each elements' position from the top to have better control.
Your problem seems to be that you only change the background color of the elements which have already been scrolled into view. Your code expects that the browser waits for your code to handle the scroll event before the browser redraws its view. This is most probably not a guarantee given by the HTML spec. That's why it flickers.
What you should do instead is to change the elements which are going to be scrolled into view. This is related to off screen rendering or double buffering as it is called in computer games programming. You build your scene off screen and copy the finished scene to the visible frame buffer.
I modified your first JSFiddle to include a multiplier for the height of the scroll area: http://jsfiddle.net/2YeZG/13/.
dad.bind('scroll', function() {
// new: query multiplier from input field (for demonstration only) and print message
var multiplier = +($("#multiplier")[0].value);
$("#message")[0].innerHTML=(multiplier*100)-100 + "% of screen rendering";
// your original code
var newScrollY = newScrollY = dad.scrollTop();
var isForward = newScrollY > oldScrollY;
var minVal = bSearch(bots, newScrollY, true);
// new: expand covered height by the given multiplier
// multiplier = 1 is similar to your code
// multiplier = 2 would be complete off screen rendering
var newScrollYHt = newScrollY + multiplier * dadHeight;
// your original code (continued)
var maxVal;
for (maxVal = minVal; maxVal < botsLen; maxVal++) {
var nxtTopSide = tops[maxVal];
if (nxtTopSide >= newScrollYHt) {
break;
}
}
maxVal = Math.min(maxVal, botsLen);
$(dadKids.slice(minVal, maxVal)).css('background', 'pink');
});
Your code had a multiplier of 1, meaning that you update the elements which are currently visible (100% of scroll area height). If you set the multiplier to 2, you get complete off screen updates for all your elements. The browser updates enough elements to the new background color so that even a 100% scroll would show updated elements. Since the browser seldom scrolls 100% of the area in one step (depends of the operating system and the scroll method!), it may be sufficient to reduce the multiplier to e.g. 1.5 (meaning 50% off screen rendering). On my machine (Google Chrome, Mac OS X with touch pad) I cannot produce any flicker if the multiplier is 1.7 or above.
BTW: If you do something more complicated than just changing the background color, you should not do it again and again. Instead you should check whether the element has already been updated and perform the change only afterwards.

Test if cursor is on the first line in a textarea (with soft-newlines)

Given a textarea with content that flows like this
––––––––––––––––––––––––––
| This is some text, which |
| wraps like this. |
––––––––––––––––––––––––––
How can one tell if the text-cursor is on the first line of the textarea?
Obviously, checking for a newline character (\n) works if one wants to see if the cursor appears before the first line break, but testing for a 'soft' line break seems more challenging.
Here is a sample jsFiddle to experiment with.
I have not yet come up with a strategy, but I suspect it may involve copying the text up until the cursor position into a cloned textarea (or div), and making the width as long as it needs to be so it doesn't wrap. If the cloned area has a width less than the original's width, then the cursor would seem to have to be on the first line. There may a simpler option, something more elegant, or (best of all) an existing and well-tested solution.
Target browsers are Webkit (Chrome/Safari) & Firefox. I.e. IE compatibility is not a concern at this time (if that makes any difference).
Thanks for reading.
EDIT: Seeking line number of text caret, not mouse cursor.
falsarella gave an excellent answer, that highlighted an ambiguity in the question. What I am seeking is whether the text cursor (“caret” may be a better word) is on the first line. I have updated the question and the jsFiddle to reflect.
I only know of one "working method". The method requires use of textarea's "cols" attribute. Long story short, set the cols to the width you want, then divide the cursor position and floor it to see if it is less than 1, thus it = line 1!
Might be easier to explain if I just show you a code example.
$("textarea").live("keyup", function(e) {
if ($("textarea").attr("cols")) {
var cols = parseInt($("textarea").attr("cols")),
curPos = $('textarea').prop("selectionStart"),
result = Math.floor(curPos/cols);
var msg = (result < 1) ? "Cursor is on the First line!" : "Cursor is on the line #"+(result+1);
console.log($("p").text(msg).text());
};
});​
however, this may still require some wired math as some col sizes may still say "line 2" when the cursor is simply at the END of line one (which technically would still be right since any character would drop to line 2)
jsFiddle
Having that 15 is the line height, this works (tested in firefox):
http://jsfiddle.net/h46jh/12/
$("textarea").click(function (evt) {
cursor_position = evt.pageY - $('textarea').offset().top;
if (cursor_position <= 15) {
alert("first line");
} else {
alert("other line");
}
});
Credits:
Find mouse position relative to element

Cannot drop a draggable where two droppables touch each other

It seems that when using two jquery UI droppables that touch each other, the droppable events are not fired correctly. If, while dragging a draggable from over one of the elements to just below it onto the next element, then the out event is fired for the first droppable, but the over event is not fired for the second. If you drop at this point, no drop event is fired.
An example is best. Try this fiddle (tested in IE7,8,9 and Chrome11). Make sure your browser's console log is open. If you drag the draggable over the first row, then slowly drag towards the second row, you'll soon see in the log that the out event for the first row is fired, but the over event for the second row is not. If you drop when this happens, the drop event is not fired.
It seems to just be a 1 pixel line in between the rows that causes the problem. Dragging one more pixel causes the over event to be fired, and the drop event to work correctly.
This looks like a bug to me, but I can't find anyone else who has used table rows as droppables and has reported the problem. I styled the table so you can see that the rows are indeed flush together with no space in between.
This is a big problem for me because in our app, the table rows are nested greedy droppables. So if the user drops when this happens, the drop is actually picked up by the outer droppable instead.
Also, we give feedback to the user in the draggable helper in the form of an icon and message that changes depending on the droppable you are over. When you drag between rows, it flickers for a moment, as it thinks you are not over any droppable when you actually are.
My questions:
Is there any fix or workaround for this issue?
Should I report this as a bug?
Update
#davin,
We did end up changing the drag function in $.ui.ddmanager to fix the event ordering. Our issue was we have nested greedy droppables. When you moved from one of these nested droppables to the other from bottom to top, the over event would actually fire for the parent last, causing bad things to happen.
So we added logic to basically check if moving from one nested greedy to another, and if so, not fire parent events.
Would it be too much to ask to have you look this over real quick and make sure our logic makes sense? There are two logical changes. If we moved from greedy child to greedy child:
Don't unset parentInstance.greedyChild
Don't fire parentInstance._over event.
Here's the code. See the lines dealing with the isParentStateChanged closure var, which we added:
drag: function(draggable, event) {
//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
var isParentStateChanged = false;
//Run through all droppables and check their positions based on specific tolerance options
$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
if(this.options.disabled || this.greedyChild || !this.visible) return;
var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
if(!c) return;
var parentInstance;
if (this.options.greedy && !isParentStateChanged) {
var parent = this.element.parents(':data(droppable):eq(0)');
if (parent.length) {
parentInstance = $.data(parent[0], 'droppable');
parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
}
}
// we just moved into a greedy child
if (parentInstance && c == 'isover') {
isParentStateChanged = true;
parentInstance['isover'] = 0;
parentInstance['isout'] = 1;
parentInstance._out.call(parentInstance, event);
}
this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
this[c == "isover" ? "_over" : "_out"].call(this, event);
// we just moved out of a greedy child
if (parentInstance && c == 'isout') {
if (!isParentStateChanged) {
parentInstance['isout'] = 0;
parentInstance['isover'] = 1;
parentInstance._over.call(parentInstance, event);
}
}
});
}
It's not a bug per se, it's a feature. It's all a matter of definitions. You've defined the tolerance of your droppable items to be pointer, which according to the docs is:
pointer: mouse pointer overlaps the droppable
When my mouse pointer is at (10,10) and the top left corner of my box ends at (10,10), is that overlapping? It depends on your definition. jQueryUI's definition is strong inequality, or strong overlap (see the relevant code). That makes sense (to me), since I'm not inside the box if I'm only on the edge, so I wouldn't want an event to fire.
Although if for your purposes you require weak inequality in the overlap condition (i.e. weak overlap), you can modify that line of code in your source, or override it, by adding:
$.ui.isOverAxis = function( x, reference, size ) {
return ( x >= reference ) && ( x <= ( reference + size ) );
};
Working example: http://jsfiddle.net/vwLhD/8/
Be aware that with weak inequality comes other bumps in the road: your out event will fire after your over event, so you might have two over events before a single out has fired. That's not so hard to handle, but you need to make sure you deal with that case.
UPDATE:
It's important to note that if you add the code I pasted above it is going to affect all other ui widgets in the scope of $ if that's important. Maybe subbing $ could avoid that.
In any case, I have a second workaround that will solve the above issue entirely, and now on every mouse movement the pointer is either in or out of every element exclusively:
$.ui.isOverAxis2 = function( x, reference, size ) {
return ( x >= reference ) && ( x < ( reference + size ) );
};
$.ui.isOver = function( y, x, top, left, height, width ) {
return $.ui.isOverAxis2( y, top, height ) && $.ui.isOverAxis( x, left, width );
};
Working example: http://jsfiddle.net/vwLhD/10/
Essentially I've made the upper condition a weak inequality and the lower one a strong one. So the borders are entirely adjacent. Now the events fire almost perfectly. Almost and not entirely because the plugin still loops through the droppables in order, so if I'm dragging from top to bottom the firing order is good because first it detects that I have left the higher element, and then detects that I have entered the lower element, whereas dragging from bottom to top the order of firing is reversed - first it fires entering the higher and only then leaving the lower.
The difference between this and the previous workaround is that even though half the time the order is not good, it all happens in one tick, i.e. over-out or out-over are always together, the user can never get stuck as in the original case and first workaround.
You can further hone this to be absolutely perfect by changing the ui code to loop through the items first according to those that have the mouse over them, and only then the rest (in the $.ui.ddmanager function). That way the mouse leave will always fire first. Alternatively you can swap the order and have the reverse order; whatever suits you better.
That certainly would solve your problem entirely.
Sounds like you might be dropping between rows which would mean you were dropping onto the table. Do you have your table borders collapsed? css border-collapse: collapsed;
I had this problem with a project i was working on.
My solution was to see check how far the draggable was over each droppable. If the draggable is 50% over the top droppable then i assume the user wants to drop on the top droppable.
Similar for the bottom.
To do this i changed $.ui.intersect;
added vars -
hw = droppable.proportions.width / 2, hh = droppable.proportions.height / 2,
lhw = l + hw,
thh = t + hh
then add some if statements
// going down
if(y2 < b && y2 >= thh){}
// going up
if(y1 > t && y1 <= thh){}
// covered
if(y1 <= t && y2 >= b){}

Categories