We are developing a small game of dropping images. We need to find the image X and Y points without an Event like mouseClick() event etc.
Please Help me to find out Points of Moving Image. i.e Points of Transit Image.
We have applied pathtransition on image.
Read the docs.
"This Transition creates a path animation that spans its duration. The
translation along the path is done by updating the translateX and
translateY variables of the node"
Just register a listener with the translateX and translateY properties of the Node you are animating. You can use the boundsInParent property to find its coordinates, including translations, relative to the parent.
Related
I'am using reactJS and want to design a component with following functionality :
Display pixelated image which is able to zoom in and zoom out at pixel level.
When clicked on image , display a marker- which can be a dot or icon at specific position.
When image is zoomIn/zoomOut, marker size and position should not change.
Even after zoomIn/zoomOut when clicked on image, marker should get repositioned at proper pixel on the image.
I am thinking of applying same logic as used in the maps/ leaflet. Like they maintain separate layers for map and markers on the map. If we zoomIn/out maps it won't affect the marker position or size, same functionality I want for the image.
Anyone with the solution or related library will be welcomed !
(For reference, I want this design for marking GCP(Ground Control Points) on the image, which requires very precise marking at pixel level)
I'm using aframe for a VR project I'm doing and I'm using checkpoint on the ground to lead the user around the 3D space. I received help before on how to create a checkpoint here
Here is the link to the most current iteration of my project -> https://museum-exhibit-demo.glitch.me/webVR.html
Is it possible to have the animation that takes you to the cylinder also change the view of the camera and height? Basically once I click the cylinder to take me to the position it will also snap my view to the text on the wall even if it is not eye height
Great Demo. I've prepared a candidate solution on glitch (app). This solution changes the height of the camera, and the horizontal direction/yaw of the camera. It does not change the pitch of the camera. Ideally any AR/VR app would minimise forcing a change of camera orientation. If you forcibly change the pitch of the camera that's like permanently tilting the floor of the user. If you just change the yaw then that just permanently changes the horizontal direction they are look. Changing the pitch can be done, but I think from a user perspective that might cause more problems than it is worth, changing the yaw is just about OK. Similar recommendations were previously mentioned in https://stackoverflow.com/a/47667912/10849562.
I'll break down the solution code by how it solves your two issues, to have the animation that takes you to the cylinder also change the height of the camera, and separately how it can change the view/direction? I'll add in line references to the solution were relevant.
Change the height to match the height of the text
First you need to know the height of the text associated with the checkpoint cylinder. One way to do this is to provide the id of the related a-text entity to the goto component. To do that I added a new component property textId to your goto component (L79). Then in each of the places where you have used the goto component the textId property was set. For example for the checkpoint cylinder associated with the Welcome! text, the goto component was changed to goto="textId: welcome" (L298).
The id of the associated a-text enitity can be accessed from methods of the goto component using this.data.textId which will be different for each goto component. Using this information within the component, the position of the a-text enitity can be found in a similar way to how you found the rig position, by finding the a-text element with document.querySelector L83 and then finding the position L93.
let text = document.querySelector(`#${this.data.textId}`);
text.object3D.getWorldPosition(textPos);
Note that instead of using text.getAttribute("position") the getWorldPosition method is used instead. That is because you have wrapped your a-text elements inside a-entity elements that also have positions set. getAttribute("position") only gives you the position relative to its parent entity, but this solution requires the absolute/world position of the text. Of course other solutions might do things different, and it's also possible to change the HTML structure of your demo so that you could use getAttribute("position"). getWorldPosition is a method from THREE.js (which A-Frame is based on) and stores the position in the textPos variable. You can use textPos in the same way as rigPos. Instead of rigPos.y you can now do textPos.y to get the height of the text as the end point of the position animation to change the height of the camera.
Note that 1.6 is taken away from the height in the solution. The default height of the camera in A-Frame is 1.6. You've handled this by reducing the position of the camera by -1.1 in the #pov entity.
Change the direction of the camera match the direction of the text
First we need to know the direction of the text with respect to its associated checkpoint cylinder. Because we now have access to the position of the cylinder the direction vector between from the cylinder to the text can be calculated (L111). From this the azimuthal angle or yaw angle of the direction from the checkpoint cylinder to the text can be calculated (L115). To do this calculation a function getYaw was created (L46) to calculate the yaw angle.
Because you have already applied a yaw rotation of 90 degrees on your #pov entity that wraps your a-camera entity, the yaw angle is calculated from the negative z-axis (0, 0, -1).
Now that you have the direction the text is from the checkpoint cylinder, you need to know the yaw direction the camera is currently pointing in. You can find this out from the rotation component of the a-camera entity. Just like finding the position of any entity, you can find the a-camera element with document.querySelector (L84) and the find its yaw angle camera.getAttribute("rotation").y (L116). You can then calculate the target yaw angle that you should set the rig to by calculating the relative angle from the camera entity to the text entity which is called targetRigYaw in the solution (L117).
Note that there are lots of applications of a mod function. This simply ensures that all yaw angles are always positive and between [0, 360] which helps simplify things when applying angles.
You could now use the targetRigYaw as the angle to set your rig to to change the view direction to look at the text. However depending on the yaw angles of the text direction and camera direction, this angle might be greater than 180 degrees. You can imagine that you could rotate left or right to end up looking in a particular direction. Unless the direction you would like to look in is directly behind you, one of the direction will be a shorted rotation than the other. L120-123 change the targetRigYaw angle so that you are always rotating in the shortest angular direction to end up looking at the text.
In order to animate the yaw in the same way as you animated the position you can add second component to the #pov entity. In the solution this is called animation__rotation (L144). The A-Frame docs describe how you can add multiple animation using the __ notation https://aframe.io/docs/1.0.0/components/animation.html#multiple-animations.
We can then set the animation__rotation component to perform an animation of the rotation of the #pov entity in a similar way to the position. The animation__rotation component is set using setAttribute to rotate from the current yaw angle of the rig to the targetRigYaw angle, and the duration of the animation is set to the same length as the position animation.
I hope this helps solve your two questions. Please let me know if you have any questions. I've added comment to the code, however there were quite a few snippets that I added that might not be obvious what they do.
I'm working on a full screen image viewer, I'll temporarily open a dev URL here:
http://www.jungledragon.org/apps/jd3/image/704/great_grey_owl.html/zoom
This viewer is responsive and scales to your browser width/height. One of its key features is being able to zoom in and out of the image using your mouse wheel. Rather than a center-based zoom, the idea is to zoom based on origin, meaning the coordinates of your mouse, allowing you to zoom into specific areas of the image.
How to reproduce the issue
If you open the above URL and have a quick play with your mouse wheel, it may appear to be working correctly. However, the math I am using is slightly off. Here is how you can reproduce the issue:
Open the above URL
Hover your mouse over the left eye of the Owl
Zoom one step using your mouse wheel, it should zoom exactly into the eye
Position your mouse on the owl's beak
Zoom one more step using your mouse wheel
You should now notice that the second zoom step did not go into the Owl's beak exactly, it seems to be slightly off, both horizontally and vertically. I'm thinking this is a result of bad math.
How it works
Here is the javascript that handles it all:
http://www.jungledragon.org/apps/jd3/js/jd3-slideshow.js
I am capturing the mousewheel event. Based upon its direction, I am increasing or decreasing the zoom level. The actual zooming is nothing more than applying a CSS class that scales the image using a CSS3 transform:
&.grow1 { #include jd-scale(1); }
&.grow2 { #include jd-scale(1.5); }
&.grow3 { #include jd-scale(2.0); }
&.grow4 { #include jd-scale(2.5); }
&.grow5 { #include jd-scale(3.0); }
Note: the above is a call to a SASS mixin that translates into the right vendor prefixes for transform:scale.
The above accomplishes the basic zooming without issues. To make origin-based zooming possible, however, a few more steps are needed. Upon doing the actual zooming, I first set the origin of the zoom in javascript, using transform-origin. Here is my helper function for setting it:
function zoomOrigin(selector, originStr) {
selector.css({'-webkit-transform-origin': originStr});
selector.css({'-moz-transform-origin': originStr});
selector.css({'-ms-transform-origin': originStr});
selector.css({'-o-transform-origin': originStr});
selector.css({'transform-origin': originStr});
}
The heart of this question is about calculating the correct origin. There are two things worthy to mention in calculating this value:
The absolute coordinates (meaning the X and Y) are relative to the image, not relative to the page
The calculation of the origin should take into account that the image has grown/shrunk based on the current zoom state
The origin calculation happens in realtime, based on the mousemove event. Here is the method that does so, with irrelevant parts removed:
$("#image-container img").mousemove(function(e) {
// user has moved their mouse. in case of zooming or panning, this means that the
// origin (center point) of those interactions need to be recalculated
// calculate the mouse offset within the zoomable object (which is different than the page-level offset)
// this relies on the parent of the element having position:relative set
var parentOffset = $(this).offset();
zoomOriginX = e.pageX - parentOffset.left;
zoomOriginY = e.pageY - parentOffset.top;
// recalculate the width and height of the image given the current zoom level
width = $(this).outerWidth() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerWidth());
height = $(this).outerHeight() + (1 + ((zoomLevelCurrent - 1)*0.5) * $(this).outerHeight());
// calculate origin percentages based on zoomed width and height
// the zoom methods rely on these variables to be set
zoomOriginPercX = (zoomOriginX / width * 100);
zoomOriginPercY = (zoomOriginY / height * 100);
});
The main purpose of this method is to correctly set the global variables zoomOriginPercX and zoomOriginPercY, which are used to set the origin (percentage) prior to zooming.
From a math perspective, my idea was to simply calculate the zoomed width of the image, and to use the offset X and Y to come to a reliable origin percentage. As the problem statement shows, I am quite close to a correct calculation, yet something is off.
Although the zooming currently works well, I want it to be perfect. It would make for quite a powerful image viewer that is really easy to implement, also for others.
Desired Effect
To start answering your question I think it's worth first clarifying the desired effect. Essentially you're looking for the same effect you'd get if you pinched to zoom on an iPhone - the 'origin' of the pinch stays exactly the same, and everything around it stretches. You can imagine pinning some stretchy fabric at the origin, and pulling the corners.
Problem
This is working fine for you if you don't move the mouse between zooms, but if you do, the origin appears to move. The cause of the problem is exactly that - you are changing the origin of the transform every time you move the mouse. Of course you do need to do this, but you are calculating the origin based on the original (100% zoomed) position of the image. The actual origin needs to be somewhere between the origin of the first zoom and the new mouse position.
In other words, CSS is just doing one transform. If you set the origin to x,y then zoom to zoom level 2, this will give the same result as if you set the origin to x2,y2, zoom to level 1, then move to x,y, and go to level 2.
Solutions
I presume you could solve the issue in several ways:
Calculate a scaling factor for the 'new' origin on each zoom
this is likely a function of zoom level, mouse position and previous origin
Calculate and apply a translation each time the origin is moved
again will depend on the current origin, zoom level and mouse position
Find another way to 'stack' transforms on top of one another.
One way to do this may be to dynamically generate a new containing div each time you and apply a scale transform to that similar to the accepted solution in this question.
Unfortunately I don't have the time to go further than this, but hopefully it points you in the right direction?
Recently I worked in a project using Flex. Its a Photo editing project. I have took a Canvas and take a image in that canvas using the code canvas.addChild(image) . Now i can move the image freely by using moving code. The image move inside the canvas and outside the canvas. I want to move the image/child only inside the canvas not outside. How can i do this?
There are two ways to do this:
Bounding Rectangle
Scroll Rectangle (or Mask)
Assuming your "moving code" is something like an Event.ENTER_FRAME handler initialized onClick, you want to make it so the image can't leave the bounds of the parent Canvas.
The first case (bounding rectangle) will allow you to drag the image within the retangle but you will always be able to see the whole image. This is how Image croppers work.
To create a bounding rectangle, you'll have to write a fairly detailed method, but the idea behind it is simple. Just get the bounding rectangle from the canvas, and don't let the image.x go below 0 and don't let image.x + image.width go beyond canvas.width. Same with height. Here's a sample Image Cropper in Flex (and the source). Check out how they did it for details.
The second case (scroll rectangle) would allow you to create more of a pan/zoom like container like you see on this Flex Pan/Zoom Map (here's the source). Also, the large image in the Flex Image Cropper on the right is an example of this second case, but they don't have the dragging. That requires that you manipulate the position of the scrollRect property on the canvas. The scrollRect property is a flash.geom.Rectangle defining the Canvas' "viewport". You then change/update the verticalScrollPosition and horizontalScrollPosition properties, so it's backwards (compared to the Bounding Rectangle).
I think if you set clipAndEnableScrolling to true on the canvas, and you drag a child image around inside of it (and image.includeInLayout = true), it should clip the image to only show up inside the canvas. But I'm guessing you want case 1. Just search those properties and you'll find some good examples on google.
Good luck, should be a fun project.
Lance
I have a component which draws a grid of things and I want a small highlight square to follow the mouse around highlighting the square that the mouse is currently over.
The whole grid is basically just one big sprite (it's a very large grid and this was faster than using pre-existing components) and the highlight square is another sprite which I'm trying to move around according to the mouse position.
So, what I have is a MouseEvent.MOUSE_MOVE handler attached to the grid sprite and this tries to determine where the mouse is and what square it's over so that it can move the highlight square to the right place. I was using localX/localY for this, but as soon as I move the highlight sprite under the mouse, these become local to the highlight and not the grid!
I was toying with stageX/Y as well, but these seemed to become pretty useless when the stage is scrolled or your component is hiding in nested display containers.
Basically, i think, you want to check the the grid components mouseX and mouseY property which will give you the mouse coordinates relative to that component. Then a little bit of maths should be able to give you what grid element you are over.
Assuming your highlight sprite is a sibling to the grid and they are both children of the main application, and you've drawn child sprites (squares) within the grid: You could add event listeners to each of the grid's square sprites. On rollover, highlight the square. Then you probably won't need to perform any translation of grid or mouse coordinates using grid.localToGlobal(new Point(targetSquare.x, targetSquare.y)) or highlightSquare.globalToLocal(grid_point).