My absolutely positioned canvas elements are blocking all the mouse events so that nothing underneath them can be clicked, same problem mentioned here and here.
I have multiple canvas layers that need to be at specific z-index's so I need to forward mouse events through the canvases. pointer-events: none; works in good browsers, but for IE9 I need javascript to do it, here is my current solution,
var evts = [ 'click', 'mousedown', 'mouseup', 'dblclick'],
canvases = $('canvas');
$.each(evts, function(_, event){
canvases.bind(event, function(evt){
var target,
pEvent;
$(this).hide();
target = document.elementFromPoint(evt.clientX, evt.clientY);
$(this).show();
pEvent = $.Event(event);
pEvent.target = target;
pEvent.data = evt.data;
pEvent.currentTarget = target;
pEvent.pageX = evt.pageX;
pEvent.pageY = evt.pageY;
pEvent.result = evt.result;
pEvent.timeStamp = evt.timeStamp;
pEvent.which = evt.which;
$(target).trigger(event, pEvent);
});
});
Working example,
jsFiddle
Questions;
1. I'm creating the new event and passing over the relevant data, would it be safe to pass the evt var with the target and currentTarget modified?
2. How can I propogate a right click?
Or does anyone have a better way to accomplish this? The other related questions are quite old.
There's no clean way to pass the events cross-browser. You can pass the (modified) event on but you can't guarantee that it will work as it might have naturally, especially cross-browser.
For right click using your code just do this: http://jsfiddle.net/6WMXh/20/
(you half used the jquery extra info part but never did anything with it)
Related
I want to replace the src attribute of all <img> elements in a certain element, that have not been loaded, because the source was not found (404).
There are quite a few topics on this here:
Check if an image is loaded (no errors) in JavaScript
jQuery or Javascript check if image loaded
Most of the answers add an eventListener on the images that wait for an error event. Ideally we'd just write something like this:
Not working example of an delegated event listener:
$("#element").on("error", "img", function(){
console.log("hey, there was an error in this image: "+$(this));
})
Another user was kind enough to point this out.
This is not working because the error event seem not to bubble, like the click event for example.
So with this knowlege, the only thing left seems to be, to iterate each image and check it for errors.
Whats the point (tl;dr)?
And here my question: What is the fasted method to iterate all images of a certain object for errors with javascript (yes, you may use jQuery). By fastest I mean: the iteration should be quite quick and unnecessary event listeners should not be placed (my problem).
This is my example code:
$(function(){
var $element = $("#element");
var replaceImgSrc = "http://www.placehold.it/100x100&text=replaced";
var allImages = $element.find("img");
for (var i = 0; i < allImages.length; i++) {
$(allImages[i]).one('error', function () {
$(this).attr("src", replaceImgSrc).addClass("not-loaded")
});
}
});
And here is a jsFiddleDemo: http://jsfiddle.net/qq2ccx05/
The performance in the jsFiddle is awful, it's better in production.
I'd like to know if there is a smarter way to solve this problem.
You could capture 'onerror' event, doesn't seem really more optimized:
var replaceImgSrc = "http://www.placehold.it/100x100&text=replaced";
$('#element')[0].addEventListener(
'error',
function(event){
var elm = event.target;
if( elm.tagName == 'IMG'){
elm.src = replaceImgSrc;
}
},
true // Capture event
);
jsFiddle
So far I have a circle with a marker.
http://jsfiddle.net/x5APH/1/
I would like to grab and drag the marker around the circle, however the current functionality only nudges the marker when you click it.
What changes can I make to the code so that the marker can be dragged around the circle while the mouse is held down?
Note
If you could update the fiddle with your solution I would greatly appreciate it.
changed some code
$(document).ready(function(){
$('#marker').on('mousedown', function(){
$('body').on('mousemove', function(event){
rotateAnnotationCropper($('#innerCircle').parent(), event.pageX,event.pageY, $('#marker'));
});
});
});
also add this code
$('body').on('mouseup', function(event){ $('body').unbind('mousemove')});
in the function
this is the jsfiddle http://jsfiddle.net/sandeeprajoria/x5APH/11/
To do anything of this sort:
On mousedown on the desired element, set:
mousemove event on the document to update the position of the target
mouseup event on the document to remove the mousemove and mouseup events you just set.
Example in plain JS:
elem.onmousedown = function() {
document.body.onmousemove = function(e) {
e = e || window.event;
// do stuff with e
};
document.body.onmouseup = function() {
document.body.onmousemove = document.body.onmouseup = null;
};
};
Personally I like to improve this further by creating a "mask" element over the whole page to capture events, so that (for example) dragging a selection or image does not trigger default browser actions (which are strangely immune to all event cancelling methods in this case...)
My question is totally like: How do I pass javascript events from one element to another? except for the fact that I need a raw JS solution.
I've got a webos app whose UI features a layering of elements that scroll in conjunction with eachother on a page. Basically I have what amounts to an iframe (not quite, but in principle), and a floating header that lives in a z-layer above it. When I scroll the elements in the iframe, it also moves the floating header up.
However, I also need to scroll the underlying doc when the header is dragged.
This is a touchscreen interface, so I'm trying onmousemove and ontouchmove events.
I've got the following code, but it doesn't seem to do anything:
setupScrollFromHeader: function setupScrollFromHeader() {
// webos enyo stuff. Don't worry about it. just know that I get the
// raw dom elements through the this.$.elem.node syntax
var body = this.$.body, header = this.$.mailHeaderUnit;
if (!header.hasNode() && !body.hasNode()) {
return;
}
body = body.node;
// end enyo specific stuff
header.node.addEventListener('touchmove', function(event) {
console.log("### touch move");
event.preventDefault();
body.dispatchEvent(event);
var touch = event.touches[0];
console.log("Touch x:" + touch.pageX + ", y:" + touch.pageY);
}, true);
console.log("### set this stuff up");
}
I'm using dispatchEvent to forward the event, per:
https://developer.mozilla.org/en/DOM/element.dispatchEvent
I've tried this with either touchmove and mousemove events by themselves, toggling prevent default, and also changing the bubbling behavior with the true/false flags.
In all cases I see the log print out, but the events are never passed to the underlying element. What am I doing wrong? Is it even possible to pass the events around this way?
So this is the right way to route events. Looks like the widget I'm talking to needed a mousedown event before receiving the touchmove events. For maximum compatibility, I added listeners for both mouse and touch, for testing in browser and on device.
I came up with the following:
setupScrollFromHeader: function setupScrollFromHeader() {
if (setupScrollFromHeader.complete) {
return;
}
var body = this.$.body, header = this.$.mailHeaderUnit;
if (!header.hasNode() && !body.hasNode()) {
return;
}
var header = header.node;
var forwarder = function forwarder(event) {
body.$.view.node.dispatchEvent(event);
};
['mousedown', 'mousemove', 'touchstart', 'touchmove', 'touchend'].forEach(function(key) {
header.addEventListener(key, forwarder, true);
});
setupScrollFromHeader.complete = true;
},
In the general browser case, you can test such forwarding with with two buttons, routing the click event from one to the other works as expected through dispatchEvent(...).
ie:
var button1 = document.getElementById('button1');
var button2 = document.getElementById('button2');
button1.addEventListener('click', function(event) {
button2.dispatchEvent(event);
}, true);
button2.addEventListener('click', function(event) {
alert("Magnets. How do they work?");
}, true);
clicking button1 will fire the handler of button2.
I've searched all across the web to find a simple way of adding touch gestures to a simple button. Basically I'm trying to find a simple way of getting the back button (which you usually see on the task-bar at the top of an iOS device) to change CSS classes from 'normal' state to 'pressed' state when pressed.
Although I'm very new to Javascript, I would prefer to use standard DOM methods rather than jQuery (or any other library). Would anyone have some complete code and explain how the JavaScript code reads an ontouchstart and ontouchend event and how these functions could be used to change CSS classes?
Any help would be greatly appreciated!
TC
ontouchstart, ontouchmove and ontouchend are managed the same as onclick, onmousemove and so.
You can apply the listeners in a <script> tag or directly in the html element.
Using JavaScript only
var back = document.getElementById("back-button-id");
back.ontouchstart = function( event ) {
// using the target property of the event
// you can reach the hitted html element
event.target.className = 'css-href-selected-class-name';
}
back.ontouchend = function( event ) {
event.target.className = 'css-href-normal-class-name';
}
Using HTML tag and callbacks
1) Declare your Javascript callbacks to swap a css class for any state
function onclickCallback( event ) {
// do something
}
function ontouchstartCallback( event ) {
event.target.className = 'selected';
}
function ontouchendCallback( event ) {
event.target.className = 'normal';
}
2) Put the callbacks into the anchor tag (I suggest to use DIV instead of A)
<div class="normal" onclick="onclickCallback( event );" ontouchstart="ontouchstartCallback( event );" ontouchend="ontouchendCallback( event );">Back</div>
Edit 1: to prevent hilight freezing during scrolling
Try to add the ontouchmove handler
ontouchmove="ontouchmoveCallback( event );"
Then declare the handler function that swap the css class
function ontouchmoveCallback( event ) {
event.target.className = 'normal';
}
Hope this helps!
Ciao.
This should get you started:
HTML:
<input type="button" id="thebutton" value="Do Stuff!" />
Javascript:
var thebutton = document.getElementById("thebutton");
thebutton.ontouchstart = function(e)
{
this.setAttribute('class', 'pressed');
var touches = e.touches; // array of all touch data
var target = touches[0].target; // what DOM element was touched
var pageX = touches[0].pageX; // coords relative to site
var pageY = touches[0].pageY;
var clientX = touches[0].clientX; // coords relative to screen
var clientY = touches[0].clientY;
};
thebutton.ontouchmove = function(e)
{
var touches = e.touches; // same fields as above
var changedTouches = e.changedTouches; // only touches which have changed
};
thebutton.ontouchend = function(e)
{
this.setAttribute('class', '');
// cleanup, if needed
};
For more details, see: http://sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
It's worth noting that MobileSafari sometimes does wonky things with touch events and form elements (input boxes in particular). You may find it's better to use a styled div than an actual input button.
EDIT: For what you're trying to do, I think you might be better served with simple click events, which generally work fine for things like button presses. Touch events are more for drag and drop, precise finger tracking etc. Try this:
thebutton.onclick = function(e) { this.setAttribute('class', 'your_class'); };
EDIT2: Now I see what you're asking for. Easiest way is this:
thebutton.ontouchstart = function(e) { this.setAttribute('class', 'pressed'); };
thebutton.ontouchend = function(e) { this.setAttribute('class', ''); };
There are a couple of libraries already for jQuery
http://plugins.jquery.com/project/multiswipe
And you also can check this demo from
http://taitems.github.com/Mobile-Web-based-Gesture-Recognition/
And you can fork the example and start working with it.
There are some options but everything its quite new.
alt text http://img197.imageshack.us/img197/9084/seperator.png
http://img197.imageshack.us/img197/9084/seperator.png
How do I create a separator, such as Google Docs in the image above, using prototype?
That separator is actually a table cell contained within a table row. It maintains a background-color and background-image to give it the effect similar to what you'd see in a desktop application.
I'm not sure to what extend you'd want to do this, but assuming that the table cell is already specified in the markup and it has the appropriate styles, you'd need to setup several things:
A mousedown handler for registering when the user has clicked on the cell.
A mousemove handler for updating the position of the separator in context of the browser window.
A mouseup handler for knowing when to stop updating the location of the separator.
There are variations on how to do this, but here's a very, very rough example:
var bMouseIsDown = false;
Event.observe('separator', 'mousedown', function() {
bMouseIsDown = true;
});
Event.observe('separator', 'mouseup', function() {
bMouseIsDown = false;
});
Event.observe('separator', 'mousemove', function(evt) {
if(bMouseIsDown === true) {
var iX = Event.pointerX(evt);
var iOffsetX = iX - Position.page($('separator'))[0];
var iWidth = $('separator').getDimensions().width;
var iElementOffset = iWidth - iOffsetX;
$(this).setStyle({
left: iX - iElementOffset
});
}
});
If you're already using Prototype, you can use the Scriptaculous draggable to get the separator to work, then hook into its events to resize the two DIVs accordingly.