To clarify my example, I want to simulate a scroll event at the center of an open window. This should affect what is reasonably the main scrolling element on a given page.
Here are some relevant pages
https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent#Values
and here's what I've tried.
scroll_evt = new WheelEvent('wheel', {
deltaY: 10.0,
deltaMode: WheelEvent.DOM_DELTA_LINE,
clientX: content.innerWidth/2,
clientY: content.innerHeight/2
});
-> wheel { target: null, buttons: 0, clientX: 520, clientY: 320, layerX: 0, layerY: 0 }
However, despite no errors, dispatching the event seems not to have any effect.
window.dispatchEvent(scroll_evt);
-> true
So I'm left to wonder: Is there some critical property I'm missing in my initializer? Is window an appropriate target for the event? I'm out of ideas.
Update
This works.
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMWindowUtils#sendWheelEvent%28%29.
var windowutils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface (Components.interfaces.nsIDOMWindowUtils);
windowutils.sendWheelEvent(window.innerWidth / 2, window.innerHeight / 2, 0, 10, 0,
WheelEvent.DOM_DELTA_LINE, 0, 0, 0, 0);
I'm still curious what's the matter with dispatchEvent.
You can get an element by position like so:
var elem = document.elementFromPoint(content.innerWidth / 2, content.innerHeight / 2);
and then apply the scroll:
elem.scrollTop += 10;
Related
I'm currently working on an automated tool that reproduce hand-drawing previously recorded on a canvas. I'm using fabric.js to create a canvas and free draw on it.
In this part of the application, the user can't draw anything but is watching the canvas being drawn on. That's why the canvas is behind an invisible div that blocks all interactions.
So far, I managed to recreate the drawing process using an asynchronous function and by triggering well-timed mouse events at specific locations.
Let's start with some mouse coordinates to use for the path to draw :
var coord = [
{x: 927, y: 115},
{x: 925, y: 116},
{x: 922, y: 116},
{x: 910, y: 115},
{x: 899, y: 114}
]
I use a custom function that simulates a mouse event at a specific location :
function simulateMouseEvent(e, eventName, x, y) {
e.dispatchEvent(new MouseEvent(eventName, {
view: window,
bubbles: true,
cancelable: true,
clientX: x,
clientY: y,
button: 0
}));
}
To start, I trigger a mousedown event as if the user was clicking on the canvas :
simulateMouseEvent(canvasElement, 'mousedown', coord[0].x, coord[0].y);
Then a for loop launches a bunch of consecutive mousemove events every 200 ms like so :
for (i = 1; i < coord.length; i++) {
await movement(coord[i]);
}
function movement(coordinates) {
return new Promise(function(resolve, reject) {
simulateMouseEvent(canvasElement, 'mousemove', coordinates.x, coordinates.y);
setTimeout(function() {
resolve('');
}, 200);
})
}
Finally, I stop the drawing by triggering a mouseup event like so :
var last = coord[coord.length - 1];
simulateMouseEvent(canvasElement, 'mouseup' last.x, last.y);
So everything works fine if the user's cursor is not above the canvas (which is what happens most of the time) even though there is a mask theoretically blocking the user's interaction with the canvas.
I believe that triggering a mouse event on a div "activates" it even if that div can't be reached. I tried adding pointer-events: none on the css rule of the canvas wih no difference. Is there a way to block real mouse cursor events while triggering fake ones ?
I recently encountered a problem trying to make a div's content horizontaly scrollable, smooth. I achieved the result I want when using a touchpad, sadly its diffrent with a mouse scrollwheel. To get the scroll intensity I use "event.wheelDelta". When logging this to the console and using a touchpad to scroll to the right I will get numbers indicating the intensity, which looks similar to this: 1, 2, 3, 4, 15, 45, 150, 50, 30, 15, 13, 4, 3, 2, 1... But when I use a scrollwheel on a mouse to scroll it looks like this: 150, 150, 150, 150, 150... That in the end causes a non smooth scrolling behavior when using the scrollwheel on a mouse. Here is a good example of the issue: https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event. Can someone help me with this? Below you see the logic of the function I use. The function gets called on a wheel event in Vue.js (v-on:wheel="replaceScrollDirection($event)").
replaceScrollDirection() {
event.preventDefault()
this.scrollPosition = document.getElementById("holideWrapper").scrollLeft
this.scrollIntensity = event.wheelDelta
this.scroll = this.scrollPosition + this.scrollIntensity * -1
document.getElementById("holideWrapper").scrollTo({left: this.scroll})
}
I'm creating a constraint between a body and a point:
var tempConstraint = Constraint.create({pointA: {x: 50, y: 50}, bodyB: body, pointB: {x: x, y: y}, stiffness: 0.1, length: 0, damping: 0.5, });
The point is also being moved around:
tempConstraint.pointA = {x: newX, y: newY};
The issue is that if pointA is moved slowly from left to right, for example, the body its dragging moves the opposite direction to what it should be. For example, if you dangle a pencil by the very tip and start moving the tip to the right, the bottom of the pencil should start to hang slightly to the left of the top as it moves. However, if I were to do that exact thing with the above code, the bottom of the pencil flies over to the right, exactly as it should if the top were being pulled left. Not sure what I'm doing wrong here but my only thought is that changing pointA is a bad idea, but I can't really come up with a better way to move the constraint point. Would creating a collision disabled, static body and attaching it to that, and then moving the body be a better way to go about this?
It's working fine for me, although I'm using a spring constraint. I've also removed the length property in the constraint so the length is auto generated:
var vw = window.innerWidth/100;
var vh = window.innerHeight/100;
var body = Bodies.rectangle(vw*50, vh*50, vw*3, vw*15, {
frictionAir: 0.02,
friction: 1,
render: {
fillStyle: "#FCED08"
}
});
var tempConstraint = Constraint.create({pointA: {x: vw*50, y: vh*50}, bodyB: body, pointB: {x:0,y:vw*7.5}, stiffness: 0.8, damping: 0.5, render: {type: "spring"}});
World.add(world, [body, tempConstraint]);
The full code is here
While trying new things, which can make your life easier, I saw something that caught my eye. When you select some part of the page and then right-click on it, you can print this specific part. So.. my guess was "Use selection API and then print it!", but it didn't really go so well. I don't really know why and when, but I'm losing focus when trying to use window.print()
This is sample code which I was trying in console on stackoverflow. Any idea how to make it work? Maybe window.print() is wrong method to use here?
setTimeout(function () {
var el = document.getElementsByClassName('default prettyprint prettyprinted')[0];
window.getSelection().selectAllChildren(el);
window.print();
}, 3000);
What I'm selecting and then click printing
What I get printed
You are losing focus because the browser will start the native printing api, which usually also includes opening a print dialog or print preview. When interacting with that dialog with a click the text loses focus.(in Chrome, other browsers not tested)
With the use of monitorEvents I can show you "what happens"
monitorEvents(window);
window.getSelection().selectAllChildren(document.getElementsByClassName('post-text')[0]);
window.print();
pointerover PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
VM324:1 mouseover MouseEvent {isTrusted: true, screenX: -1644, screenY: 153, clientX: 276, clientY: 60, …}
VM324:1 pointermove PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
VM324:1 mousemove MouseEvent {isTrusted: true, screenX: -1644, screenY: 153, clientX: 276, clientY: 60, …}
VM324:1 pointerdown PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0.5, …}
VM324:1 mousedown MouseEvent {isTrusted: true, screenX: -1644, screenY: 153, clientX: 276, clientY: 60, …}
VM324:1 pointermove PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0.5, …}
VM324:1 mousemove MouseEvent {isTrusted: true, screenX: -1634, screenY: 205, clientX: 286, clientY: 112, …}
VM324:1 pointerup PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
VM324:1 mouseup MouseEvent {isTrusted: true, screenX: -1634, screenY: 205, clientX: 286, clientY: 112, …}
VM324:1 click MouseEvent {isTrusted: true, screenX: -1634, screenY: 205, clientX: 286, clientY: 112, …}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using chrome in this example I clicked a button in the printing dialog UI. This mouseup event caused the focus to go away and apparently the selection ending up cancelled. Possibly chrome inserts the printing dialog as a shadow DOM object, letting interactions on it having events for the document.
What I found out is that if I use the escape key to exit the dialog that this event is not transferred to the global event listeners, causing it to not having any effect and letting the selection persist.
So, if you wanted to print that selection you could use a code like the code below:
+function() {
// Create an iframe to make sure everything is clean and ordered.
var iframe = document.createElement('iframe');
// Give it enough dimension so you can visually check when modifying.
iframe.width = document.width;
iframe.height = document.height;
// Add it to the current document to be sure it has the internal objects set up.
document.body.append(iframe);
// Get the node you wish to print.
var origNode = document.querySelectorAll('.post-text .default.prettyprint.prettyprinted')[0];
// Clone it and all it's children
var node = origNode.cloneNode(true);
/**
* copied from https://stackoverflow.com/questions/19784064/set-javascript-computed-style-from-one-element-to-another
* #author Adi Darachi https://stackoverflow.com/users/2318881/adi-darachi
*/
var copyComputedStyle = function(from,to){
var computed_style_object = false;
//trying to figure out which style object we need to use depense on the browser support
//so we try until we have one
computed_style_object = from.currentStyle || document.defaultView.getComputedStyle(from,null);
//if the browser dose not support both methods we will return null
if(!computed_style_object) return null;
var stylePropertyValid = function(name,value){
//checking that the value is not a undefined
return typeof value !== 'undefined' &&
//checking that the value is not a object
typeof value !== 'object' &&
//checking that the value is not a function
typeof value !== 'function' &&
//checking that we dosent have empty string
value.length > 0 &&
//checking that the property is not int index ( happens on some browser
value != parseInt(value)
};
//we iterating the computed style object and compy the style props and the values
for(property in computed_style_object)
{
//checking if the property and value we get are valid sinse browser have different implementations
if(stylePropertyValid(property,computed_style_object[property]))
{
//applying the style property to the target element
to.style[property] = computed_style_object[property];
}
}
};
// Copy the base style.
copyComputedStyle(origNode, node);
// Copy over all relevant styles to preserve styling, work the way down the children tree.
var buildChild = function(masterList, childList) {
for(c=0; c<masterList.length; c++) {
var master = masterList[c];
var child = childList[c];
copyComputedStyle(master, child);
if(master.children && master.children.length > 0) {
buildChild(master.children, child.children);
}
}
}
if(origNode.children && origNode.children.length > 0) {
buildChild(origNode.children, node.children);
}
// Add the styled clone to the iframe. using contentWindow.document since it seems the be the most widely supported version.
iframe.contentWindow.document.body.append(node);
// Print the window
iframe.contentWindow.print();
// Give the browser a second to gather the data then remove the iframe.
window.setTimeout(function() {iframe.parentNode.removeChild(iframe)}, 1000);
}();
Hi I know we can trigger click event . but I want to know that can we trigger mousemove event without any actual mouse movement by user.
Description :
I want to show a message when user select something. on canvas ,my canvas is of full height and width,when user click on a button the canvas shows up. when user do mouse movement he see a message "Click and drag on any part of the web page". this message follows the mouse movement of the user.
What I want to do :
When user click the button he should see the message that "Click and drag on any part of the web page". and message must follow wherever user moves the mouse.
Problem :
User is not able to see the message after click until he/she moves his mouse.
Code:
function activateCanvas() {
var documentWidth = jQ(document).width(),
documentHeight = jQ(document).height();
jQ('body').prepend('<canvas id="uxa-canvas-container" width="' + documentWidth + '" height="' + documentHeight + '" ></canvas><form method="post" id="uxa-annotations-container"></form>');
canvas = new UXAFeedback.Canvas('uxa-canvas-container', {
containerClass: 'uxa-canvas-container',
selection: false,
defaultCursor: 'crosshair'
});
jQ(function() {
var canvas = jQ('.upper-canvas').get(0);
var ctx = canvas.getContext('2d');
var x,y;
var tooltipDraw = function(e) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
var str = 'Click and drag on any part of the webpage.';
ctx.fillStyle = '#ddd';
ctx.fillRect(x + 10, y - 60, 500, 40);
ctx.fillStyle = 'rgb(12, 106, 185)';
ctx.font = 'bold 24px verdana';
ctx.fillText(str, x + 20, y - 30, 480);
};
canvas.addEventListener('onfocus',tooltipDraw,0);
canvas.addEventListener('mousemove',tooltipDraw,0);
canvas.addEventListener('mousedown', function() {
canvas.removeEventListener('mousemove', tooltipDraw, false);
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
}, false);
});
}
jQ('body').on('click', '.mood_img_div', function() {
// alert("soemthing");
toggleOverlay();
activateCanvas();
});
I have made a function which is called after click but the message is not visible. Is there any way to call it for the first time with message and show is everytime when user uses mouse.
I have replaced jQuery with jQ because I am making my own plugin(this is not causing the problem)
A good native approach is to use dispatchEvent method on EventTarget.
It dispatches an Event at the specified EventTarget, invoking the affected EventListeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().
Try
// 1. Add an event listener first
canvas.addEventListener('mousemove', tooltipDraw ,0);
// 2. Trigger this event wherever you wish
canvas.dispatchEvent(new Event('mousemove'));
in your case it should trigger mousemove event on canvas element.
(Triggering events in vanilla JavaScript article can be also useful):
var elem = document.getElementById('elementId');
elem.addEventListenter('mousemove', function() {
// Mousemove event callback
}, 0);
var event = new Event('mousemove'); // (*)
elem.dispatchEvent(event);
// Line (*) is equivalent to:
var event = new Event(
'mousemove',
{ bubbles: false, cancelable: false });
jQuery:
Try this with jQuery trigger method:
$('body').bind('mousemove',function(e){
// Mousemove event triggered!
});
$(function(){
$('body').trigger('mousemove');
});
OR (if you need triggering with coords)
event = $.Event('mousemove');
// coordinates
event.pageX = 100;
event.pageY = 100;
// trigger event
$(document).trigger(event);
OR
Try using .mousemove() jQuery method
let coordX = 0; // Moving from the left side of the screen
let coordY = window.innerHeight / 2; // Moving in the center
function move() {
// Move step = 20 pixels
coordX += 20;
// Create new mouse event
let ev = new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: true,
clientX: coordX,
clientY: coordY
});
// Send event
document.querySelector('Put your element here!').dispatchEvent(ev);
// If the current position of the fake "mouse" is less than the width of the screen - let's move
if (coordX < window.innerWidth) {
setTimeout(() => {
move();
}, 10);
}
}
// Starting to move
move();
Albeit it is probably possible to mimic such an event as shown in Andrii Verbytskyi's answer, most of the time, when you want to do it, it is because of an "X-Y problem".
If we take OP's case for instance, here we absolutely don't need to trigger this mousemove event.
Pseudo-code of current implementation :
function mousemoveHandler(evt){
do_something_with(evt.pageX, e.pageY);
}
element.addEventListener('mousemove', mousemoveHandler)
function clickHandler(evt){
do_something_else();
}
element.addEventListener('click', clickHandler);
And what we want is to also call do_something_with in the click handler.
So OP spends some time to find a way to trigger a fake mousemove, spends another amount of time trying to implement it, while all that is needed is to add a call to do_something_with in clickHandler.
Both mousemove and click events have these pageX and pageY properties, so the event can be passed has is, but in other case, we could also just want to pass it with a fake object containing required properties.
function mousemoveHandler(evt){
do_something_with(evt.pageX, evt.pageY);
}
element.addEventListener('mousemove', mousemoveHandler)
function clickHandler(evt){
do_something_else();
do_something_with(evt.pageX, evt.pageY);
}
element.addEventListener('click', clickHandler);
// here we won't have pageX nor pageY properties
function keydownHandler(evt){
do_something_else();
// create a fake object, which doesn't need to be an Event
var fake_evt = {pageX: someValue, pageY: someValue};
do_something_with(fake_evt.pageX, fake_evt.pageY);
}
element.addEventListener('keydown', keydownHandler);
Note : you are mixing jQuery.on and element.addEventListener, so you might need to pass the originalEvent property of the jQuery event object.