I'm using A-Frame on my project. There's this cursor component that enables you to interact with the elements by clicking, which is quite similar to DOM clicking.
However, the cursor clicking no longer works after I implemented my Pointer Lock.
Pointer Lock works well for me, I can walk around and look around in my scene, and the cursor always appears in front of me.
Why is the clicking not working? I can confirm that the clicking works fine when I haven't entered the Pointer Lock mode. Thanks!
Link to my demo:
http://zichao.co/exp/_simu/
I have added a listener on the '#floor'. If you successfully clicked the floor, the console should say 'hello'.
When you try to implement your PointerLock using the apis, first you need to define an element, and call element.requestPointerLock, is that right? The issue here is that element.
I took the a-scene as the element. What you should do is to take the canvas as the element - the canvas that is rendered later by a-frame, or three.js.
A $(document).ready() function is not able to return you the canvas because it is inserted into the dom by three.js, i.e. the dom is ready before canvas is created. What I do now is to set an interval to loop and check if canvas is created, and then activate the PointerLock.
Solved.
Related
I am implementing a functionality where I can add, drag, and delete "sticky notes" on a webpage. The app is built in Vue js but it also renders content in an iframe. All the notes that are added to the page have to be on top of the iframe (which is almost 80% of the main .vue page), therefore positioning here is important and I also have to preserve the positions because I must render the notes on the same position on next page reload. The problem is that there's a lot of lag in dragging the "note" element.
The "sticky note" itself is a very lite weight separate component.
I have noticed that this because of the iframe that's present on the vue page because when I inspect the DOM in the browser and delete the iframe and then try dragging the "note" component then it works smoothly.
Things I have tried:
Use throttling: I tried to use loadsh.throttle but that does not make any difference.
Inject "sticky note" code inside the iframe: I tried to inject a sticky note element into the iframe and append it to iframe's body. It actually makes the dragging very smooth. But I don't want to go ahead with this solution because then I will have to write a lot of extra code to maintain the state of multiple notes (which can be done easily with Vue js).
In this solution, instead of using the document of the main page to attach events for dragging, I attached all the events to iframe.contentDocument.
So the question here is how do I make the drag smooth while using vue.js
Sandbox Link: https://codesandbox.io/s/affectionate-jang-3c1hw?file=/src/components/HelloWorld.vue
In this gif, the background is actually the iframe, I have reduced its opacity to hide it.
I could not actually include the iframe in sandbox code because of cross-origin problems but I have included a lot of extra content in that sandbox to make it heavy.
UPDATE:
Using the chrome task manager, I found that the page is only taking max 200MB memory and the GPU process is taking another 200MB. I am running this on a system with 16GB RAM. So I don't think it's a memory issue. But there is a sudden spike in the CPU consumption when I start dragging the element (up to 40%).
UPDATE:
I have found the fix for this problem. The actual problem wasn't lag but it was mouse trailing i.e. the draggable element wasn't able to catch up with the fast moving mouse cursor. And the slowness was due to e.preventDefault in the dragMouseDown method inside Note.vue. Just removing the e.preventDefault fixed all the problems. Also just adding a return false at the end of dragMouseDown method seems to cause the same amount of lag.
function dragMouseDown(e) {
e = e || window.event;
// e.preventDefault(); --> this line causes the mouse trailing issue
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
// return false; --> adding this line also causes mouse trailing problem.
}
So for now I have just removed the preventDefault from this function. But I tried searching and could not find any explanation of this behavior. Also I am not sure if not cancelling the event can cause any other issue.
The problem is that you're working with mousemove without using requestAnimationFrame to debounce. Here's a working example using debounce (CodeSandbox link)
Generally, anytime you're trying to animate with javascript, you want to use requestAnimationFrame. Another thing you could try is using transform to change the position of the element instead of absolute positions.
Here's the MDN reference on requestAnimationFrame.
Here's an article by Paul Irish about using transform instead of absolute positioning to speed up a drag/drop.
As your extra description in the comments,
It starts to lag when these a lot of other content on screen. There's
a v-for in the sandbox. make it do more iterations and it will start
to laggy
The problem you met is the Dom elements were too many on your page then caused high memory usage. (Actually I tried <div v-for="i in 10000" :key="i">", then it took around 3GBs of memory), finally, everything works slowly and laggy
If your page has tons of Dom elements, you may have to consider dynamically add only visible items into the Dom tree when scrolling.
Even there are some packages that already implements this feature.
Below is one demo which uses RecycleScroller of vue-virtual-scroller:
100K items in the Codepen
You will see even the number of the items are 100,000, it still works smoothly.
PS: you may notice the below statement in the user guide of the above package=vue-virtual-scroller
The browsers have a size limitation on DOM elements, it means that
currently the virtual scroller can't display more than ~500k items
depending on the browser.
Currently a canvas element (which is built by a third party) on my webpage is intercepting drag events (because it assumes you want to drag something within the canvas), but this can "trap" the user within the canvas, especially if they zoomed in on it on mobile. I want the user to be able to scroll/swipe up and down on the canvas to reach the rest of the page above and below it, just like it were any other HTML element. They should be able to click into the canvas still, I just don't want the canvas to intercept regular page scrolling.
EDIT: I was able to find wheel and mousewheel events in the third-party code and remove them from the canvas object, resolving the issue for desktop users. Which event would be relevant for mobile users? I tried removing touchmove without success.
your issue seems to be that you're not correctly differentiating between scrolling and dragging.
I suggest you only prevent the default scrolling when the dragging actually takes place
How can activate the drag -and-drop feature inside the canvas tag ?
As far as I know, there is no built-in drag and drop within a canvas, because a canvas is a literal context that you draw things on. Canvas-based games constantly refresh and redraw all elements.
Basically, a canvas requires a lot of manual, fine-tuned assembly of colors, though it can be performant under circumstances where you want that type of manual, decided control
When a user clicks on an object that seems to be within your canvas, you have to calculate where that mouse event's X and Y coordinates would fall, and determine which actions can be performed onclick on whichever thing is drawn there.
Normal DOM (not so in a canvas or iframe) will emit an event from the element you clicked, and will bubble up through all parent elements saying that some target element was clicked, and this fired event will have lots of data about that click event
A canvas is kinda like having a real painting: rather than an assembly of objects, there is nothing to drag, just a bunch of data about which pixels are which colors.
Normally, HTML elements have an attribute [draggable], but you would still need to manually reposition the element on mouseup or whatever, based off of the screen, or closest non-staticly placed parent. This question might be helpful: HTML5 Canvas Drag and Drop Item
You should search around instead of asking a question like this, in my opinion
So... I am working on an interaction design project and I want to create a sencha-style gesture scroll for content areas. The way I've done it so far, is to attach touchmove/start/end events to the content area, and it translateY's the contents. It works in on desktop with mousemove/up/down events, but it jumps around like crazy with touch. I'm not sure whats wrong.. here is a link to a prototype.
**requires webkit.
http://apps.omorphos.com/gesture-scroll
I think it is an issue with the event response, but I tried and haven't been able to nail it down. Any help is greatly appreciated!
So, I figured this out.
What I was doing was attaching the touch event to the list tag itself.. and, that works fine on desktop with mouse events; however, with touch, the target changes and touchend doesn't fire properly.
So, what I did, and what I believe sencha does, ... and I had originally implemented but went in a different direction... is have an absolutely positioned element with a transparent background color floating above the element that will be manipulated. All of the touch events will be captured by that DIV and then the elements below can be manipulated without losing the event data.
In the new version I used HammerJs ... more info: http://eightmedia.github.io/hammer.js/
but i'm pretty sure you could just use standard events; but the good thing about hammer js, is that it will translate touch events to mouse events for testing in the browser, this also means making the coordinates for touch the same as mouse, so you can access mouse event coords via
e.gesture.touches[0].pageX
e.gesture.touches[0].pageY
which let's you write less code.
Part 2:
Additionally... part of the issue is... how do you click on the content/components(e.g. links) below the screen.
How you do this... is you take the coords from the event handler and pass them through this native Javascript function...
var a = document.elementFromPoint(x, y);
this will return the dom element. and all you have to do is trigger the click/tap event.
Which would be great, except it will pick the element with the highest z-index.. so that is your screen obj(the one that is capturing all of the touch events). So, what you need to do, is hide the screen after a tap is registered, and then execute this function 200ms later, and then bring back the screen to capture whatever events.
You can do this with this function...
$(theScreen).on('tap', function(e){
screen.hide();
var hit = document.elementFromPoint(e.gesture.touches[0].pageX, e.gesture.touches[0].pageY);
$(hit)[0].tagName !=="A" || $(hit).trigger('click');
setTimeout(function(){screen.show()},300);
});
And, that is how I solved it!
My code is not super annotated, but you can find it at the link below:
Updated example:
http://apps.omorphos.com/gesture-scroll/v2/
I am making a javascript game and I would like to be able to add a main menu but I don't know exactley how. I am lookign up for a way to make filltext() clickable but to no avail. I have looked it up but have found no answer that suites my needs. The games protoype can be viewed here: sketchy.idreesinc.com . Does anyone know anyway to implement this? I am using javacript and HTML5's canvas element but I would prefer javascript. Thanks!
Things to know about HTML and canvas first
DOM
HTML elements are part of the DOM (the Document Object Model) which is the data structure of a webpage. DOM elements can have trigger events (like click) and event listeners react to those events.
browser
Your web browser converts the DOM elements into pixels on your screen. It also handles input and figures out what element's events to trigger if you click on the page.
canvas
The canvas element allows you to render bitmap images. You basically set the colors on a grid of pixels through some javascript calls to make pretty pictures.
what that all means
When you create a link element in HTML (the <a> tag) the browser renders the text and attaches a click listener to the element so the link actually works.
When you use javascript to draw the pixels on the canvas the browser's understanding of the DOM stops at the canvas. The browser knows about the DOM and the DOM knows about the canvas but it doesn't keep track of the individual items drawn in the canvas.
The answer
You can't actually attach an event to the text in the canvas but there are many ways to get the desired behavior of click the text, something happens.
One way would be to attach a click event to the canvas but instead of a simple event listener that always runs this event listener would need to check to see if the click happened on the text or somewhere else on the canvas.
Event listener functions get called with an Event argument which has information about the event.
Things to google
Some quick reading about these should get you started towards a working menu.
registering javascript event listeners
javascript event mouse coordinates