Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid changing scale while dragging over scaled holder #1379

Open
flackr opened this issue Oct 30, 2022 · 13 comments
Open

Avoid changing scale while dragging over scaled holder #1379

flackr opened this issue Oct 30, 2022 · 13 comments
Labels
enhancement New feature or request widget properties changes to widget properties

Comments

@flackr
Copy link
Collaborator

flackr commented Oct 30, 2022

When you scale a holder (or ancestor of the holder) it scales all of its children implicitly. This is similar to the way setting onlyVisibleForSeat hides not only the widget but all of its children as well.

However, when you start dragging a widget it is temporarily removed from the holder. This also lead to the widget temporarily flicking into view for players who couldn't see it (see #1356). We similarly have a size flicker in that while dragging the widget loses the scale it gets from its container and when you drop it gets it back.

There are two main ways we could avoid this:

  1. Keep the scale it had during the drag.
  2. Similar to Hide dragged items while over hidden container. #1356, apply the scale of the current hoverTarget, i.e. the scale it would get when you drop it.

I prefer option 2 as I find it difficult to accurately position widgets in holders when their size changes after you let go, and it also fixes the main problem of the size flickering as you drag within a holder.

@96LawDawg
Copy link
Collaborator

One thing that might be nice to do if this gets implemented, is to have a small visual effect on the card similar to what PCIO does to clearly show that a card has been picked up. In PCIO, when you pick up a card, it rotates slightly to the right and enlarges very slightly, and returns to normal when you drop it. I created some JSON a few months ago that does something similar. See https://discord.com/channels/770758631146782780/862352981747695616/1006061670147293315. Demo in https://virtualtabletop.io/r85o.

@robartsd
Copy link
Collaborator

robartsd commented Nov 2, 2022

I like option 2, but would add the holder's rotation as well. Might name the property hoverInherritTransform.

I wrote the most code that currently deals with drag and drop with transformed parents. You mentioned the DOMMatrix object on Discord a while back and I thought it might be helpful in making improvements (haven't had the time needed to explore that yet).

@96LawDawg
Copy link
Collaborator

Yes, definitely rotation as well.

So in the setup you both are imagining, the widget would transform to be the proper scale and rotation of the holder that it is over. But that means it would change scale as the mouse moves away from the holder. What about this scenario. You have a holder in the bottom right that is scaled to take smaller looking widgets. You want to drag a widget from the bottom right to the upper left to another holder that takes those some smaller looking widgets. But in between is an open area with no holders. So you drag from the bottom right. When you pick it up, it is small. You leave the area of the holder and it goes full-sized again. You get to the upper left and it gets small again. That could be jarring. So could there be an option to keep the scale and rotation it was when you picked it up and it stays that way until you drop it (then it takes on the scale and rotation of whatever holder it is in or if not a holder, then the room default).

@robartsd
Copy link
Collaborator

robartsd commented Nov 3, 2022

So in the setup you both are imagining, the widget would transform to be the proper scale and rotation of the holder that it is over. But that means it would change scale as the mouse moves away from the holder.

Yes, that is how it is being pictured.

So could there be an option to keep the scale and rotation it was when you picked it up and it stays that way until you drop it (then it takes on the scale and rotation of whatever holder it is in or if not a holder, then the room default).

We could add another property to widgets while they are being dragged to indicate which widget the was parent when the move started. Then all clients could add _absoluteScale and _absoluteRotation from the source holder if the holder has a particular property set. Perhaps these new properties could be called draggingOrigin and draggingInheritTransform.

@flackr
Copy link
Collaborator Author

flackr commented Nov 3, 2022

So could there be an option to keep the scale and rotation it was when you picked it up and it stays that way until you drop it

My only concern with this is it would be hard to place widgets not knowing how they will transform into the target container. E.g. if the holder has alignChildren: false it could be hard to ensure you drop it in the right spot to pile with a pile in that holder. It could definitely be an option and perhaps coupled with a "shadow" which does use the dragTarget transform you could avoid changes to the dragged item but still know where exactly it is in the dragTarget space.

@96LawDawg
Copy link
Collaborator

I would only envision this is an option that the room designer would use knowing the potential issues. In my scenario, the holders in the bottom right and bottom left would have the same scale and rotation. Enabling that option would definitely look better as during the drag as the widget would not resize twice. That would be more jarring than not being sure it would go into a precise spot (in my opinion). So please make it an option for that kind of scenario.

@flackr
Copy link
Collaborator Author

flackr commented Nov 3, 2022

Yep, agreed that for that use case keeping the last transform makes sense. Another possibility is it remembers the last dragTarget it was over to support transforming to different targets. We could always have a multi-value setting like "draggingInheritTransform": null | "source" | "target" | "last" where "source" would do what you're asking, and "last" would keep the transform of the last holder it was over.

@96LawDawg
Copy link
Collaborator

Yep, agreed that for that use case keeping the last transform makes sense. Another possibility is it remembers the last dragTarget it was over to support transforming to different targets. We could always have a multi-value setting like "draggingInheritTransform": null | "source" | "target" | "last" where "source" would do what you're asking, and "last" would keep the transform of the last holder it was over.

I like that. Seems to cover every use case I can think of.

@robartsd
Copy link
Collaborator

robartsd commented Nov 3, 2022

Yep, agreed that for that use case keeping the last transform makes sense. Another possibility is it remembers the last dragTarget it was over to support transforming to different targets. We could always have a multi-value setting like "draggingInheritTransform": null | "source" | "target" | "last" where "source" would do what you're asking, and "last" would keep the transform of the last holder it was over.

That would work if this is a property of the widget being dragged. I was envisioning the setting more as a property of the holder.

@ArnoldSmith86
Copy link
Owner

Wouldn't it be easier to just leave the card as a DOM child at some point?

@flackr
Copy link
Collaborator Author

flackr commented Nov 3, 2022

Wouldn't it be easier to just leave the card as a DOM child at some point?

Good question. I suspect there are many aspects to dragging which require moving the dragged item out. e.g. escape ancestor clips, elevate to a higher z-index if it's being contained within it's parent stacking context. Unless we move the dragged item into the hover target it wouldn't support the target case. Also, without moving it out from the source it wouldn't relayout the remaining items in a holder if their relayout is dependent on DOM layout.

All of this is just guessing what could be problematic - I don't know in practice how often parents clip. I think they do enforce a stacking context so the z order could be behind other holders.

@robartsd
Copy link
Collaborator

robartsd commented Nov 4, 2022

Wouldn't it be easier to just leave the card as a DOM child at some point?

Good question. I suspect there are many aspects to dragging which require moving the dragged item out. e.g. escape ancestor clips, elevate to a higher z-index if it's being contained within it's parent stacking context. Unless we move the dragged item into the hover target it wouldn't support the target case. Also, without moving it out from the source it wouldn't relayout the remaining items in a holder if their relayout is dependent on DOM layout.

All of this is just guessing what could be problematic - I don't know in practice how often parents clip. I think they do enforce a stacking context so the z order could be behind other holders.

I've had the same thought about leaving the widget DOM element as a DOM child of whichever holder effects we want to propagate. If we do this, then it would be subject to the styling of the parent widget (clipping, stacking context, visibility).

Positioning would not be an issue because the widget being dragged will be taken out of the flow due to being position:absolute (currently all widgets are, but the only thing that matters is that the DOM element of the widget being dragged is taken out of the flow).

@flackr
Copy link
Collaborator Author

flackr commented Nov 4, 2022

That would work if this is a property of the widget being dragged. I was envisioning the setting more as a property of the holder.

Yeah, I was originally imagining this too, though if we have global defaults #1380 it becomes easy to opt everything into the behavior if desired. So then the question is if there are use cases for sometimes applying these changes and sometimes not would they be based on the container or the item being dragged.

Either way, I think we could change this to be a property of the holder by saying something about whether its transform is sticky or not, e.g.
hoverInheritTransform: "sticky" | true | false

Where sticky would result in the last behaviour where the container is remembered even after it's no longer the current drag target. This would be slightly different than having it defined on the dragged widget so of course it would be good to think about what makes more sense for the use cases where the behavior is sometimes desired.

@96LawDawg 96LawDawg added enhancement New feature or request widget properties changes to widget properties labels Nov 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request widget properties changes to widget properties
Projects
None yet
Development

No branches or pull requests

4 participants