As the canvas uses its own local coordinate system, I've tried several methods to ascertain the global X,Y of mouse clicks and translate them to the coordinate system. I do this by subtracting the left margin and top margin from the canvas itself via either jQuery
.offset()
or by using
getBoundingClientRect()
in Javascript.
Sadly, both of these will be affected by browser scrolling. I may just be missing a property (I use e.clientX and e.clientY because I know they're cross-browser capable) that would give me a more definite value... I have been perusing all the properties of a DOM element and none of them seem to quite give me what I need...
I need a scroll-independent way of determining how far from the document top I am to relate mouse clicks to a coordinate system.
...or am I being an idiot and there's a cross-browser way to detect mouse clicks relative to an object? Thanks in advance.
Best method I can find would be to use a jQuery method such as $('#').offset() and then account for scrolling. Alternatively, Object.getBoundingClientRect() can be used, but I'm not sure on the cross-browser compatibility.
Nobody else felt like chiming in, lol.
Related
My understanding is that CTRL-mousewheel zooms are an accessibility feature, built into the browser in question (I am currently testing in Chrome and Opera, both if which use the CTRL- zoom).
This won't ever really be needed for accessibility, however, as the app will not be for the general public. And CTRL-wheel zoom has a nice benefit out-of-box as compared with standard mousewheel zoom over elements: It seems that Angular ui-sortables work perfectly at any zoom/scale.
Unfortunately, from other answers I've found on SO, there is no way, when using CTRL-wheel, to zoom selectively : the browser can only zoom everything. For me, this includes position:fixed overlays scaling at the same time as the main viewport, which is no good.
So I set up some code for scrolling as per whichever element the mouse cursor is over, eg. scale the main viewport using the mousewheel, only if the mouse if over that viewport element.
The problem is that ui-sortable does not behave correctly, when using it for only a single element. I've used scale with transform-origin set at 50% 50% but still, when I drag the ui-sortables at any scale other than 1:1, they appear way off to the left. Any ideas on how to begin to tackle this?
This isn't a problem in Angular's sortable adaptation, rather it's an issue in the underlying jQuery-ui 1.9.2 positioning functions around line 4000 (_generatePosition or maybe one of the others). I believe that as the browser does not modify the actual dimension values during scale or zoom, and the formulae provided in that library do not account for scaling (that I can see), there is no easy fix, since jQuery ui.sortable needs scale-accurate values to calculate correct displacements. (I tried modifying the formula to account for this, but without success.)
The simplest workaround for the present is to manually change the width() / height() of your individual list elements, as seen here. This may require being selective about just what you scale using width() / height(), and what you change using scale (which is generally easier).
For a long time, I've been looking for a way to detect when a DOM element's size or position has changed. It could be because the window resized, or because new child elements were added to the element, or because new elements were added around this element, or because CSS rules have changed, or because the user has changed their browser's font size. There are a huge number of reasons that an element's size or position would change.
I could hook event handlers for many of those events, but I think there are cases that aren't covered. I had hoped to use MutationObservers to just watch the element's offsetWidth or clientWidth, but it looks like those only apply to DOM attributes, not Node properties (or maybe that's just what Webkit implements). So, to be truly bulletproof, it looks like I would need to run a polling loop anyway.
Is this correct? Have I missed something important? Is polling the only bulletproof way to detect when an element's size or position has changed?
Edit
To give a little more context, this isn't tied to any one particular use case. For me, it has come up time and time again. In my current situation, I was hoping to have a canvas that is set, via CSS, to be 100% width and height of its parent. I want a script to adjust the canvas's width and height properties when its offsetWidth or clientWidth changed (this is for WebGL, where the width and height properties affect the framebuffer resolution). In another project, I wanted to have an element expand in height to fill whatever remaining space was in the user's browser window. I have come across this situation time and time again and, inevitably, the solution seems to be:
Listen to window.resize
Hook into any code that you write that might change the DOM (or maybe use Mutation Events or Mutation Observers)
Have a periodic polling operation to clean up any missed cases
(most people stop at 1, and maybe do a little of 2)
I just wanted to make sure I wasn't missing something vital.
Incidentally, in my WebGL situation, listening to window.resize is sufficient (and is somewhat preferable, because then the canvas dimensions and rendering resolution change at the same time).
You might could do it with CSS animations. Check out http://developer.streak.com/2012/11/how-to-detect-dom-changes-in-css.html and similar. I suppose it won't handle all your requirements though, now that I read through it some more.
A co-worker pointed me to a technique that uses the underflow and overflow events. I haven't tried it, and I have no idea what kind of browser support there is (looks like Chrome and FireFox, and it should work in IE by synthesizing the same events that browser would look for, but I have no idea which versions support the technique).
As of 2019, you have access to:
ResizeObserver to fire callback on size change. Be careful here, it's not supported everywhere yet.
MutationObserver that could be used for position, but I guess that's a bit overkill. Well supported though.
IntersectionObserver as a bonus, that allows you to check for intersection with ancestors. Extremly useful to optimize stuff, especially in WebGL. This is pretty well supported.
I was wondering if there was any jQuery library that will allow us to change the perspective of an image.
I know that modern browsers already support vendor specific rotate() in CSS but it doesn't quite give the desired result. Most of them just vary the width of the image but doesn't shrink the height of one side and increase the height of one side to produce the effect that you are viewing the image from another angle.
Any more details that you may need, please tell me. Thanks!
EDIT
I already tried transforms but they don't increase the height of the side that is moving towards you and decrease the one that is moving away from you. And I don't do full rotations, i just tilt the image a few degrees so the change in height has to really be there
Have a look at script3D.js
http://minimal.be/lab/Sprite3D/
could be usefull for 3D css animations.
CSS3 has 2D-transforms and 3D-transforms. While the first is well supported (by all browsers, not by all used versions [1]) the second is currently only supported by mozilla and webkit [2]. Both features mostly need vendor-prefixes.
And of course you can animate them with jQuery, if you want to.
One major barrier to creating immersive experiences in the browser (using WebGL and similar) is the set of limitations placed on mouse control.
For instance a first person shooter control scheme essentially requires the program to grab the mouse and re-center it so as to allow infinite movement in any direction for the cursor. This is a no-no because it would give the web programmer too much control. Hopefully one day we will see a plugin that allows a site to request permission to move the mouse to allow this behavior.
However I think there are some ways to improve things without going that far. I am wondering if it's possible to allow access to the mouse position once the mouse moves off of the window (focus is still on window)?
I was playing this game using Google Chrome: http://www.chromeexperiments.com/detail/x-wing/?f=
and my biggest issue was that to get to a corner, I have to carefully keep my mouse on the corner of the browser window. If I push it off the window my ship would stay where the mouse's last window position was, which is not exactly in the corner. And I would crash into the wall.
To make this better, the browser should be able to receive mouse updates when the mouse is outside of the window. In the context of this type of game if the mouse leaves the window it should continue to send updated positions to the browser.
Is there any provision for this?
To answer your question, no, you can't get mouse events from outside the window (including its position).
There is the Mouse Lock API, which is designed specifically for the case you describe. It locks the cursor to the current window. Support is virtually non-existent right now, but one day..!
A hint :
function thumb_mouse_down(e) {
e.target.setCapture();
return false;
}
function doc_mouse_up(e) {
e.target.releaseCapture();
}
setCapture() does the trick. A working example is here.
That really seems like a far bigger security issue than allowing the developer to reposition the cursor. The answer is no, there's no such thing. And there probably won't ever be one. Sorry!
Update: I was, of course, talking about the capturing outside the window that would be a problem. It's very likely that there will ever be an API that locks the mouse, maybe after asking the user's permission. As nickf pointed out, they're already working on it -https://www.w3.org/TR/pointerlock/
Original defunct link - http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html
The idea: I'm creating a simple WebGL script (using mrdoob's wonderful three.js) that allows the user to control a camera in a world of objects. The camera is supposed to simulate traditional first person shooter cameras (reference Team Fortress 2, for example). That is, the camera moves only when the mouse moves.
The issue: in Javascript, the only way to detect mouse movement is if the cursor itself moves. By comparison, FPS games don't show the cursor -- they only base the movement of the camera off of how the mouse itself moves. So, you can move your mouse all over the mousepad in any direction and it always works.
On a browser though, since camera movement is based on the cursor, you can't move but so far. When the cursor hits the edge of the screen, the user is unable to look any further in that direction (e.g. you move your mouse to the left edge of the screen, you can't look left any more).
The solution: I've thought of two solutions, but neither of which I know how to implement. Either
After the mouse is moved, the javascript resets it to the center of the screen. That way, after every mouse movement the player is free to again move in any direction. The issue with this is that, based on the research I've done, Javascript is unable to control the position of the user's mouse (understandably, as it would be an incomparable nuisance on malignant sites).
Or, the mouse "wraps" around the screen. Meaning, when the user reaches one edge of the screen, the mouse would simply continue on to the other side of the screen. (see: http://www.digicowsoftware.com/detail?_app=Wraparound) However, it appears that this too is not an inherent capability of javascript, but instead is only something a third party program could solve.
So, does the problem make sense? If so, is there any way I can implement the above solutions, or is there another one I'm missing?
For anybody that still interested in achieving this, it is now somewhat available.
Using:
document.addEventListener('pointerlockchange', changeCallback, false);
see example http://www.html5rocks.com/en/tutorials/pointerlock/intro/
The worldwide community is currently working on a draft spec to solve this issue. What you're stating is called "mouse-locking". I've worked a little on the first phase of this standard to help lay out what's needed. Please, vote for these issues and subscribe to the indicated mail lists in order for all of us to get this issue corrected ASAP.
Chromium Bug: http://code.google.com/p/chromium/issues/detail?id=72754
Firefox Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=633602
W3C Mail list: http://www.w3.org/Bugs/Public/show_bug.cgi?id=9557
Draft proposal: https://docs.google.com/document/d/1uV4uDVIe9-8XdVndW8nNGWBfqn9ieeop-5TRfScOG_o/edit?hl=es&authkey=CM-dw7QG
However, there's still a way you can achieve your objective (which is the other way i found): A native plugin that takes control of the mouse.
(I'm making a game too which is a FPS but currently won't be released due to this limitation)
You're right about all of this. Standards-based web tech isn't going to give you mouse capturing like you want.
That said: you might be able to craft (or find) a special SWF that can collect mouse movement data and pass that to javascript. It won't constrain cursor movement, although you can use CSS to conceal the cursor while mouse capturing is active. But it might be able to e.g. continue firing "move mouse left" events even when the cursor has reached the left edge of the screen.
Any such SWF will probably fail to capture movement when the cursor is outside the viewport i.e. over the browser chrome.
Given that it's apparently not possible to do this as such in HTML5/Javascript, what about this variant: treat the mouse position (not mouse movement) as representing the rate of turning.
So if the mouse is more than a certain threshold left of the center, the camera turns left; the farther left the mouse is, the faster the camera turns. To stop turning, the player moves the mouse back toward the center.
To me this is an annoying UI, at least initially, but maybe the player would get used to it. Since we don't have any perfect solutions, it may be worth trying. You can mitigate the problem by allowing the arrow keys to work the way they do in many FPSes, rotating the camera when they are pressed down.