daybrush / moveable

Moveable! Draggable! Resizable! Scalable! Rotatable! Warpable! Pinchable! Groupable! Snappable!
https://daybrush.com/moveable/
MIT License
10.08k stars 618 forks source link

How to deal with sequence of different actions #395

Open josvos opened 3 years ago

josvos commented 3 years ago

The "vanilla" example code for the callbacks shown in the handbook (https://github.com/daybrush/moveable/blob/master/handbook/handbook.md) doesn't support multiple operations in sequence. E.g, doing a rotation works fine, but starting a drag a resize afterwards undoes the rotation. I would like to have it all working together, similar to the demo (https://daybrush.com/moveable/) ;-).

Background: I want to do all kinds of operations on the frame and finally take its CSS props (transform, width, height, etc.) to store as new CSS for an element (a div acting as some zone).

daybrush commented 3 years ago

@josvos

You have to set all the values of the transform. translate, rotate, scale

const transform = translate(${translate[0]}px, ${translate[1]}px) rotate(${rotate}deg) scale(${scale[0]}, ${scale[1]});

or use helper

const [helper] = React.useState(() => { return new MoveableHelper(); }) const targetRef = React.useRef(null); return

Target
    <Moveable
        target={targetRef}
        draggable={true}
        resizable={true}
        rotatable={true}
        onDragStart={helper.onDragStart}
        onDrag={helper.onDrag}
        onResizeStart={helper.onResizeStart}
        onResize={helper.onResize}
        onRotateStart={helper.onRotateStart}
        onRotate={helper.onRotate}
    />
</div>;
josvos commented 3 years ago

@ set all the values: ok, but the order does matter, as translate => rotate differs from rotate => translate. I could calculate one matrix/matrix3d(...), e.g. using the rematrix package, and administer the accumulated transformation. But the problem is still that the transform origin is kept at the original center. Also, a resize breaks the accumulated transformation, as it needs recalculating the translate.

@ moveable-helper: tried it and yeah, this is exactly the behavior I need (except one thing, see below). But moveable-helper pulls in scenejs and more, a huge amount of code, just for this, which looks like overkill.. One problem I also still see: how do I specify an existing transform to start with, that keeps being honored by the subsequent actions?

daybrush commented 3 years ago

@josvos If possible, keep the order of T => R => S

Also, as you say, the order of transforms can be changed.

It's still in beta and try this feature


onBeforeRenderStart={e => {
    e.setTransform(`translate(0px, 0px) rotate(30deg) scale(1, 2)`);
}}
onDragStart={e => {
    e.setTransformIndex(0);
}}
onDrag={e => {
    e.target.style.transform = e.transform;
})
onRotateStart={e => {
   e.setTransformIndex(1);
   e.dragStart && e.dragStart.setTransformIndex(0);
}}
onRotate={e => {
    e.target.style.transform =  e.drag.transform;
}}
josvos commented 3 years ago

I guess the onBeforeRenderStart should get parameters for the transform (translate x/y, degree etc.) from a saved state of previous actions, that has to be updated at on{Drag,Rotate}End events?

And how to deal with resize? Should I adapt the width/height and correct the translate accordingly (dependent on the resize "direction")?

daybrush commented 3 years ago

@josvos

Right. Save the previous value to the last end event or progress event.

onDragEnd={e => {
    e.lastEvent && setState(....);
}}

And resize, scale, and rotate all change the translate value.

josvos commented 3 years ago

I made some progression and I can now do mixed set of drag/resize/rotate actions while the frame responds correctly (note that I didn't try scale, skew etc. yet). I'm happy to share the code when ready (although it is wrapped in a Vue component now).

But now the next question is how to initialize the frame with the saved properties. So, when I save the translate, rotate, width, and height values, how to create the frame again and continue to perform actions, saving the properties again, etc. All attempts I tried so far resulted in a bad initial frame and/or strange behavior when performing actions.

josvos commented 3 years ago

Hi, any suggestions related to my last question, about how to save and restore/initialize transform properties between sessions?

mr-romeijn commented 3 years ago

@josvos Did you eventually figure out the best way to do this ( & within a vue component? ). Im using the vue moveable package (tho it hasn't been updated in about 6 months) and i'm running into similar issues and questions as you and hit this issue. Would love to see your take on it. I'm struggling a bit with the combination of rotations and transforms. Same reasons as stated above.