How to convert screen coordinates to scene coordinates - javascript

I created a a-scene with some objects to drag. The final purpose is exactly what aframe-click-drag-component does. Unfortunately, this component is not compatible with the last version of A-Frame.
I created a custom component.
AFRAME.registerComponent('draggable', {
init: function () {
/* Some code */
}
});
I use the aframe-mouse-cursor-component to be able to get the mouseenter and mouseleave events on the draggable object, and detect when the mouse position allows the user to select the object.
I added an EventListener on document.body to know when the dragging starts:
document.body.addEventListener('mousedown', function (e) {
// start dragging
});
I continuously update a global variable to update the mouse position when a mousemove occurs:
document.addEventListener('DOMContentLoaded', function () {
document.body.addEventListener('mousemove', function (e) {
window.mouseX = e.clientX;
window.mouseY = e.clientY;
});
});
This way, I can easily get the position of the mouse during the dragging. But I do not know how to convert the position of the mouse on the client to a position in the Virtual Reality (restricted to a 2D plan to make it possible).
I solved this issue by using the raycaster coming from the cursor in the middle of the a-camera, but I want to drag the objects with the mouse-cursor, and this component does not have a raycaster.
I also tried to use some maths to convert the mouse coordinates to a coordinates set relative to the camera, without success (essentially because of the screen size which can vary).
What solutions are available? I would like to update the click-drag or the mouse-cursor, but I have no knowledge of THREE.js.

See https://github.com/mayognaise/aframe-mouse-cursor-component or https://github.com/mrdoob/three.js/blob/dev/examples/js/controls/DragControls.js or https://www.npmjs.com/package/aframe-click-drag-component for examples
The main chunk of code is like:
canvas.addEventListener( 'mousemove', function () {
var mouse = new THREE.Vector2();
var rect = canvas.getBoundingClientRect();
mouse.x = ( (event.clientX - rect.left) / rect.width ) * 2 - 1;
mouse.y = - ( (event.clientY - rect.top) / rect.height ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
}, false);

Related

How to achieve Google Maps-like scrolling behavior on Here Maps API for JavaScript?

I am using Here's Maps API for JavaScript and trying to achieve a scrolling behavior on mobile similar to what Google Map's API's has.
When I want to scroll by touching the map, scrolling the page should not be always prevented, only if the Map's DRAGGING behavior is disabled.
I have tried calling window.scroll() with the corresponding Y parameters extracted from pointer events, but it is not as smooth as the browser's default scrolling.
How should I use drag or some other event targeting the Map to scroll the page?
This code should work for you:
let mapevents = new mapsjs.mapevents.MapEvents(map),
behavior = new mapsjs.mapevents.Behavior(mapevents);
let startY, endY = 0;
map.addEventListener('dragstart', function(evt) {
if (evt.currentPointer.type == 'touch' && evt.pointers.length < 2) {
startY = evt.currentPointer.viewportY;
behavior.disable(H.mapevents.Behavior.DRAGGING);
}
});
map.addEventListener('drag', function(evt) {
if (evt.currentPointer.type == 'touch' && evt.pointers.length < 2) {
endY = evt.currentPointer.viewportY;
window.scrollBy(0, (startY - endY));
}
});
map.addEventListener('dragend', function(evt) {
behavior.enable(H.mapevents.Behavior.DRAGGING);
});
In dragstart and drag callbacks the scrolling is disabled only when pointer's type is touch and number of pointers is 1. That makes it possible to zoom & pan the map with two fingers on touch device and also with mouse on desktops / laptops.
Note, that method behavior.isEnabled(feature) doesn't disable the feature. For that you need to use behavior.disable(opt_features) See https://developer.here.com/documentation/maps/topics_api/h-mapevents-behavior.html
You can allow scrolling on the map by:
Disable the map's dragging behavior on dragstart and capture the Y coordinate.
Enable the map's dragging behavior on dragend and capture the Y coordinate.
Scroll the page by the difference of the start and end Y coordinates on dragend.
var mapEvents = new H.mapevents.MapEvents(map);
var beh = new H.mapevents.Behavior(mapEvents);
var startY, endY = 0;
map.addEventListener("dragstart", function(evt) {
startY = evt.currentPointer.viewportY;
beh.disable(H.mapevents.Behavior.DRAGGING);
});
map.addEventListener("dragend", function(evt) {
endY = evt.currentPointer.viewportY;
window.scrollBy(0, (startY - endY));
beh.enable(H.mapevents.Behavior.DRAGGING);
});

Zoom-IN/OUT canvas in pdf-reader, cause mouse coordinates to change it's position

I am currently implementing a functionality to place an canvas over pdf in pdf-reader so that we can draw on top of canvas, so the pdf in which canvas is placed can be zoomed-in and out to much extent, and I have to ensure that canvas should also resize as per the pdf, so that drawing on top of it remains intact, for resizing canvas I am using the canvas.style.width , drawing.style.height to resize it when pdf-resizes.
But now my concern is that on resizing mouse-pointer changes its position, for instance in the attached image my mouse is in bottom-right and it draws in top-left, due to shifting in mouse coordinates.
I am using RxJS for drawing, and capturing events, but I am not been able to figure out how to take care of mouse position in summary, I want coordinates to scale as per canvas resize.
private captureEvents(canvasEl: HTMLCanvasElement) {
// this will capture all mousedown events from the canvas element
this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
.pipe(
switchMap((e) => {
// after a mouse down, we'll record all mouse moves
return fromEvent(canvasEl, 'mousemove')
.pipe(
// we'll stop (and unsubscribe) once the user releases the mouse
// this will trigger a 'mouseup' event
takeUntil(fromEvent(canvasEl, 'mouseup').do((event: WheelEvent) => {
console.log('e', e.type, e);
const prevPos = {
x: null,
y: null
};
this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
console.log('coordinatesArray', this.coordinatesArray);
})),
// we'll also stop (and unsubscribe) once the mouse leaves the canvas (mouseleave event)
takeUntil(fromEvent(canvasEl, 'mouseleave')),
// pairwise lets us get the previous value to draw a line from
// the previous point to the current point
pairwise()
)
})
)
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = canvasEl.getBoundingClientRect();
// previous and current position with the offset
const prevPos = {
x: res[0].clientX - rect.left,
y: res[0].clientY - rect.top
};
const currentPos = {
x: res[1].clientX - rect.left,
y: res[1].clientY - rect.top
};
this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
// console.log('coordinatesArray', this.coordinatesArray);
this.drawOnCanvas(prevPos, currentPos);
});
}
Moreover, I am not generating the new canvas on every zoom-in/out, I am just modifying the it's height/width as per dimensions of page on top of which it is present.
I eventually solved it after spending a hell lot of time.
I have posted the answer in relevant thread that will be helpful to others going through the similar problem.
https://stackoverflow.com/a/56363476/5763627

How do get I the clickable point from a html element?

how do I get the x,y coordinates from a HTML element relative to screen?
I'm using x,y from getBoundingClientRect() as below, but as you can see in the blow image, if I use move the cursor to this x,y position, the curson is in the middle between 0 and + buttons not the 5 button, which is the target button.
What am I missing?
JS code:
var e = document.querySelector('input[id=five]');"
var r = e.getBoundingClientRect();
var x = r.x;
var y = r.y;
MoveMouseTo(x,y); // imaginary call, the real cursor move is done by C# but I can share the code, as needed.
Image:
NOTE: if this aditional info may help, it's a C# application with embedded browser.
const getCoords = (e) => {
var x = e.clientX
var y = e.clientY
var xx = e.screenX
var yy = e.screenY
console.log(x, y, "client")
console.log(xx, yy, "screen")
}
You're going to want to assign this function to a onmousemove event to the outermost div containing the UI for your calculator. This should at least show you the difference between a screen X,Y and a client X,Y
https://www.w3schools.com/code/tryit.asp?filename=FVXZOK1SPTR0
You can try to add an event listener on your element and use the event to retrieve the coordinates of the mouse.
const $element = document.querySelector('input[id=five]');
$element.addEventListener('mousemove', handleMouseMove);
function handleMouseMove (event) {
console.log('Offset from the screen coordinates', event.screenX, event.screenY);
// The client refers to the element you are bound to;
console.log('Offset from the client coordinates', event.clientX, event.clientY);
};

FabricJS - Better solution to centering object on cursor when selected?

I would like selectable objects to snap their center to my mouse cursor on click. The only modification allowed to the user in this case is moving the object, no scaling, rotating, etc. Simply updating the position of the object on mousedown or selected will update its position only until the moving event is fired, where the object will snap to its original position and then begin following the mouse.
rect.on('moving', moveHandler);
function moveHandler(evt) {
var mousePnt = $canvas.getPointer(evt.e);
rect.set({
left:mousePnt.x - rect.width*0.5 , top:mousePnt.y - rect.height*0.5});
this.setCoords();
}
This is what I've come up with to center a selectable rectangle on the cursor, but I'm certain it's firing two movement events. Is there a way to override that original positioning. Or should I instead write my own mousedown, mouseup, and moving listeners to mimic the default dragging behavior?
You solution is fine if no rotating or scaling is involved.
You are not executing anything more than necessary if not the .setCoords that during a movement is optional since it will be called on mouseUp when the translation is finished.
If you want to take the mouseDown approach, changing the position once for all, you can use this logic:
var canvas = new fabric.Canvas('c');
canvas.add(new fabric.Rect({width: 50, height: 50}));
canvas.on('mouse:down', function(opt) {
if (this._currentTransform && opt.target) {
var target = opt.target;
target.top = this._currentTransform.ey - target.height/2;
target.left = this._currentTransform.ex - target.width/2;
this._currentTransform.left = target.left;
this._currentTransform.offsetX = this._currentTransform.ex - target.left;
this._currentTransform.offsetY = this._currentTransform.ey - target.top;
this._currentTransform.top = target.top;
this._currentTransform.original.left = target.left;
this._currentTransform.original.top = target.top;
this.renderAll();
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.min.js"></script>
<canvas id="c" ></canvas>
You have to modify all the transform information that fabric noted down on the mouseDown event before the your mousedown handler is executed.

Trying to drag ship on canvas from left to right in Space Invaders clone

I have a "ship" that I have drawn on my canvas and I want to be able to drag it left and right on the bottom of the canvas when it is clicked. I have done some research but I'm having no luck.
I'm assuming I use onMouseDown to do this so I have this when the page loads...
canGame.onMouseDown = canCanvas.onMouseDown(e);
and here is the code that creates my ship
gShip = spriteNew("MediumSpringGreen", 230, 950, 150, 20);
From there I am not really sure what to do. I have a gameUpdate function which moves the invaders down the screen. A gameInit function that will draw the invaders and ship on the screen. Also I have a gameDraw function which draws everything on the screen. I have a few others which are not really important for my issue.
Here is the jsfiddle with the full source code. For some reason though it will run on my browser when I run the HTM file but not in jsfiddle.
http://jsfiddle.net/f66bk/2/
Like I said in comment, the best way of doing this kind of behaviour is by using the events mouseup, mousedown and mousemove.
I defined a var named isMouseDown to know that the ship is dragged that I set to true on mousedown and false on mouseup:
canGame.onMouseDown = function() { isMouseDown = true }
canGame.onMouseUp = function() { isMouseDown = false }
You will also need the event onmousemove to get your mouse position to redraw your ship properly:
canGame.onMouseUp = function(event) { moveShip(event, this) }
In the function moveShip, you can get your mouse position and set the position of your ship properly:
function moveShip(evt, obj) {
if(!isMouseDown)
return;
var target = evt.target || evt.srcElement,
rect = target.getBoundingClientRect(),
offsetX = evt.clientX - rect.left;
gShip.Rect.X = offsetX - gShip.Rect.Width/2;
}
Here is your jsfiddle :)

Categories

Resources