Trying to wrap my head around this particular use case of D3 v4 zooming. My example so far is available here:
http://bl.ocks.org/gmarler/f6d17432f6eea34318bff477eb9ebd27
I'm able to get my initial Partition Layout to draw as required (I've left out complexities such as text positioning and color), but I'm not getting very far with zooming properly.
The goal is to zoom whenever one of the svg rect elements is clicked on.
And by "zoom", I mean something somewhat different than the stated default behaviors:
Completely disable anything other than a click on an element - no drag, panning, or mouse wheel activity normally associated with D3 zoom.
When an svg rect element is clicked on, the element expands (or contracts) in the X dimension only, such that its left side abuts the left side of the top level svg's g container, and its right side abuts the right side of the top level svg's g container.
In other words, the element clicked on becomes exactly the width of the chart.
All other g/rect elements vertically "above" the clicked one should scale/translate appropriately.
All other elements vertically "below" the clicked one don't really need to change, as the one we've clicked on will take up 100% of the width of the chart container.
So, here's how far I've gone:
I've calculated the scaling factor (k) - not sure I've done it right. The goal is to set the scaling factor to whatever will make the width of the clicked element expand/contract to the width of the svg.
And I've calculated the transform for x (tx) to be whatever will cause the left side of the g element encapsulating the rect element to align with the left side of the svg.
Using k and tx, I create a zoom transform with d3.zoomIdentity.translate(tx, 0).scale(k)
Now I select all of the g elements that contain rects, tear the current transform="translate(x,y)" apart, and apply the zoom transform to the x portion of the translate - this should move the left side of the element to the left side of the svg
Next, I select the rect under each g element, and apply the zoom transform to the width attribute
This seems to get me closer to the end goal, but I'm sure I'm missing something:
Is it really necessary for me to tear apart the transform="translate(x,y)" the way I am for the g elements?
If I click on certain elements more than once, the scaling keeps increasing. I need to both:
Keep the original zoom ratio so that I can reset to it, or go back to it simply by clicking on the lowest rect element
If an element is clicked on, it's already at 100% width - I need to never allow scaling past 100% width
clicking on any given element the first time expands it to 100% width as expected, but not all elements' ancestors properly scale - I don't care if the the ancestors expand either end past the edge of the viewport, but some of the ancestor elements leave the viewport entirely, which I cannot account for.
Related
I've been messing around with UI Automation and Scrolling. I found that in notepad if you take the bounding rectangle of the scrollable window, subtract out the size of any scrollbar bounding rectangles, it scrolls perfectly. However, trying the same thing against ISpy++, which aligns the top treeview item perfectly on each scroll even when there may be one or two pixels of the next item in the view at the bottom.
The problem with that is it reports the scroll amount requested was set. Say the view was 6.384914% and you do all the math to calculate where you scroll the view to the next window, say it came out to 24.382102 (completely made up number), so you scroll there, but it really didn't because it aligned the top item which otherwise would be missing a few pixels based on height of window. You read back where scrolling decided to set it and it says it was 24.382102 (note that when the scroll actually moves a full item it does report a different final scroll position and so can be calculated out).
What would solve the above is if we knew the actual bounding rectangle of the view that represents the 6.384914% so that those extra pixels wouldn't be considered part of the view, when you move to the next page, you're now align to where the next page would actually start. In this case of the tree, the bounding rectangle would be aligned to all items that fit plus the final spacing (or that could be part of the top of the view).
I wanted to scroll and get the data perfectly without any overlaps (except on final page of course, but that could be calculated out when you have the proper aligned boundaries that matches scrolling) or extra spacing.
Is there a way to do that, that I'm missing?
TIA!!
I have a grid of buttons (3 by 3 for this example). When a button is clicked, it rotates 180 degrees. As it rotates towards 90 degrees, it increases in scale. Once it passes 90 degrees and rotates towards 180, it decreases back to it's original size.
Unfortunately, this is a 2D game so it seems that the layers are determined by the hierarchy, which is created in the order the buttons are spawned. This causes some ugly overlap issues when the tiles scale up, when I really just want whatever button is clicked to be brought to the front.
The common solution seems to be to set the sibling index, but that will not work in this case because the buttons are held in a canvas using a Grid Layout Group, and changing the sibling index causes the buttons to be reordered.
Add a canvas component to your button and use sortOrder to modify the rendering order of it.
I want to make a controller button prompt in my game where it says 'Press X to Join', but I want the X to be an actual graphic of the 'X' button, like how it is in many games. How would I go about doing that? Right now I'm just putting a big space in my prompt text and putting a UI Image of the button in it, but I want to know if there's a better way about it.
For the sake of scaling to different resolution sizes, you would wanna scale the anchors of the UI elements correctly and have an appropriate parent-child relation tree in Unity's hierarchy.
The red box is the hierarchy.
The 2 green boxes shows ways of scaling the anchors.
The orange box shows the end result of it.
Anchors in combination with their relative position, allows Unity's UI elements to scale up and down according to screen size.
So for example if you say that an anchor is at 0.25x, that would be that its anchored at 25% of for example the x axis. Same goes if you set it for the y axis, just the vertical instead of horizontal anchoring.
You can use the anchors to adjust a minimum and a maximum anchor which the elements may float within, they may have the same value as well, then it's a fixed anchor point.
To clarify, I suggest that you use a panel to hold 2 text elements and the image with the X, each text element being on the left and right side of the X instead of having spacing inside the UI text elements. To keep correct spacing you then must use anchor points. This way your spacing stays correct despite changing screen and resolution sizes.
Please note that the "left", "top", "right" and "bottom" values are then relative to the anchor points. So if you move "left" 5 pixels, those 5 pixels will be out from the relative anchor point.
Here's the values I used:
My left text is at 0.25x, right text is at 0.8x, image is at 0.5x.
The panel holding the 3 is at 0.2 minimum x to 0.8 max x, same goes for y axis.
The largest parent panel is stretched to max fit in the canvas.
I have a general question (I know I should present specific code with a problem, but in my case the problem is of a more general nature).
In Processing, let's say I make an ellipse:
ellipse(30, 30, 10, 10);
Now, is there a way to get the pixels where this ellipse is on the canvas? The reason would be to have a way of creating user interaction with the mouse (for instance). So when someone clicks the mouse over the ellipse, something happens.
I thought of turning everything into objects and use a constructor to somehow store the position of the shape, but this is easier said than done, particularly for more complex shapes. And that is what I am interested in. It's one thing to calculate the position of an ellipse, but what about more complex shapes? Are there any libraries?
Check out the geomerative library. It has a way to check whether the mouse is inside any SVG shape. I can't remember off the top of my head but it works something like you make a shape:
myShape = RG.loadShape("shape.svg");
and a point:
RPoint p = new RPoint(mouseX, mouseY);
and the boolean function contains() will tell you if the point is inside the shape:
myShape.contains(p);
It's better to use a mathematical formula than pixel-by-pixel checking of the mouse position (it's much faster, and involves less code).
For a perfect circle, you can calculate the Euclidean distance using Pythagoras' theorem. Assume your circle is centred at position (circleX,circleY), and has a radius (not diameter) of circleR. You can check if the mouse is over the circle like this:
if(sq(mouseX-circleX)+sq(mouseY-circleY) <= sq(circleR)) {
// mouse is over circle
} else {
// mouse is not over circle
}
This approach basically imagines a right-angled triangle, where the hypotenuse (the longest side) runs from the centre of the circle to the mouse position. It uses Pythagoras' theorem to calculate the length of that hypotenuse, and if it's less than the circle's radius then the mouse is inside the circle. (It includes a slight optimisation though -- it's comparing squares to avoid doing a square root, as that can be comparatively slow.)
An alternative to my original mathematical answer also occurred to me. If you can afford the memory and processing power of drawing all your UI elements twice then you can get good results by using a secondary buffer.
The principle involves having an off-screen graphics buffer (e.g. using PGraphics). It must be exactly the same size as the main display, and have anti-aliasing disabled. Draw all your interactive UI elements (buttons etc.) to this buffer. However, instead of drawing them the normal way, give each one a unique colour which it uses for fill and stroke (don't add any text or images... just solid colours). For example, one button might be entirely red, and another entirely green. Any other RGB value works, as long as each item has a unique colour. Make sure the background has a unique colour too.
The user never sees that buffer, so don't draw it to the screen (unless you're debugging or something). When you want to detect what item the mouse is over, just lookup the mouse position on that off-screen buffer. Get the pixel colour at that location, and match it to the UI element.
After you've done all that, just go ahead and draw everything to the main display as normal.
It's worth noting that you can cut-down the processing time of this approach a lot if your UI elements never (or rarely) move. You only need to redraw the secondary buffer when something appears/disappears, animates, or changes size/position.
so i have a uiview that is initialized with a frame that has the height and width that is present for the user, i want the user to be able to draw inside this frame but when the user presses a button, i want the view to cut off that extra wasted space so that the frame is only as big as what the user was drawing. I tried to do something like this
CGRect boundbox = CGPathGetBoundingBox([myPath CGPath]);
boundbox.origin.x = self.frame.origin.x;
boundbox.origin.y = self.frame.origin.y;
self.frame = boundbox;
However, this does not remove that extra wasted space, it only resizes the view, so that the drawn content looks smaller than previously. What i would like to do instead is to remove
that "whitespace", i was thinking if it could be possible to scale up the content of the uiview, but im not sure.
To clarify what i mean:
The red border is the area / frame that the user can draw on, the text in the middle is a drawing, when the user presses a button, i want the frame to only encircle the drawing like in figure 2.
Now lets say i have the following scenario, i have drawn a circle on the middle of the screen.
When i then press the button, the scale remains the same but the circle is still in the same position but we have now changed the draw area, so the circle / drawing will look like its cut off like in figure 4.
What i want to do is to move the drawing / bezier path so that it is positioned in the middle of the frame. So that the red area encircles the blue circle.
[EDIT]
Given your drawings. A UIView will not re-position items in it when you change it's frame property (or it's CGRect). In this case you will need to track the items drawn YOURSELF, and then when the button is pressed perform the object translations yourself.
What that means is you will have to find the object that is left most, the object that is topmost, then move all objects left by that amount, and up by that amount so that all objects are (as a grouping) top-left aligned within the view's frame. After this you will need to self recognize which object is the right most touching and which object is the bottom most touching.
NOW, since you have already moved the items left-top, the right most point will define your frame width, and the bottom most point will define your frame height.
IF YOU SO DESIRE, you should be able to zoom in using the properties below after you have done this.
[First Answer]
If I understand your question correctly, you may want to still perform your box frame manipulation, but if you wish to scale you may want to look into the
contentScaleFactor or
contentStretch
properties.
contentScaleFactor should scale both dimensions based upon a singular floating point value (i.e. xWidth * scaleFactor, yHeight * scale factor).
contentStretch is a CGRect which means that it should scale each dimension (axis) separately.