Apply Undo Redo on elements that can dragable (drag and drop)

馋奶兔 提交于 2019-11-30 10:01:59

问题


I want to implement functionality on the svgElements that can be dragged with javascript how could I do this...

I have implemented this with mouse up

When mouse up occurs, I save the x and y position, object id, object type (circle, rect, etc.)

Can any one tell...is this good way to implement?


回答1:


I see a little issue in the example, you forget sometimes this.

var history = {
    stack   : [],
    counter : -1,
    add     : function(item){
        this.stack[++this.counter] = item;
        this.doSomethingWith(item);

        // delete anything forward of the counter
        this.stack.splice(this.counter+1);
    },
    undo : function(){
        this.doSomethingWith(this.stack[--this.counter]);
    },
    redo : function(){
        this.doSomethingWith(this.stack[++this.counter]);
    },
    doSomethingWith : function(item){
        // show item
    }
};



回答2:


If you're asking how to implement undo/redo functionality in general, it's fairly simple: you have an array of actions and a counter. You push new elements onto the array when actions occur and step backwards when people hit undo.

Very basic implementation:

var history = {
    stack   : [],
    counter : -1,
    add     : function(item){
        this.stack[++counter] = item;
        this.doSomethingWith(item);

        // delete anything forward of the counter
        this.stack.splice(this.counter+1);
    },
    undo : function(){
        this.doSomethingWith(this.stack[--counter]);
    },
    redo : function(){
        this.doSomethingWith(this.stack[++counter]);
    },
    doSomethingWith : function(item){
        // show item
    }
};

Note that there should be basic error checking to see that counter doesn't go beyond bounds and that you may want to pass 'undo' info into doSomethingWith in the case of an undo, but all that is app specific.




回答3:


cwolves describes a good structure for the undo/redo functionality.

You are correct, that during mouse-up, you'll want to store the history, but you'll also want to store the original location of the object(s) being manipulated during mouse-down so you'll have have it when you undo the move.

If you end up taking it a step further, and allowing scaling, then you'll want to store the complete original transform e.g. "translate(10,10) scale(1.2,1.2) rotate(90)", for history, but also so that you'll have a baseline to apply the drag-scaling action to.




回答4:


I found a better structure without counter, index shift or limit handling problems. Simply 2 stack for "done" and "reverted" action that are balancing.

var history = function() {
    this.done = this.reverted = [];
    var self = this;

    this.add = function(item) {
        self.done.push(item);

        // delete anything forward
        self.reverted = [];
    };

    this.undo = function() {
        var item = self.done.pop();

        if (item) {
            self.reverted.push(item);
        }

        return item;
    };

    this.redo = function() {
        var item = self.reverted.pop();

        if (item) {
            self.done.push(item);
        }

        return item;
    };
};



回答5:


There are some issues with the above codes. I attempted to use those and found out that I had to hit undo twice initially before it started going down the array.

So say I have done[0] done[1] done[2]. done[2] was just saved into the array. If I hit undo, it returns that. You dont want that. It is replacing what is already there. But hitting undo again, THEN you get your previous code.

Mine, as I have a drag and drop editor with different modes of edits. Drag and Drop Elements. Edit Elements HTML/Pictures. Sorting elements.

$("#neoContentContainer") contains all editor html. And you can call editor_add on clicks, mousedowns ect... seeing it is a function you can easily call.

function editor_add(){
    undo.push($("#neoContentContainer").html());
    update_buttons();
}
function editor_undo(){
    var item = undo.pop();
    // prevent undo/redo from undoing to the same HTML currently shown. 
    if(item == $("#neoContentContainer").html()){
        redo.push(item);
        item = undo.pop();
    }
    if(item){
        redo.push(item);
        $("#neoContentContainer").html(item);
    }
    update_buttons();
}
function editor_redo(){
    var item = redo.pop();
    if(item == $("#neoContentContainer").html()){
        undo.push(item);
        item = redo.pop();
    }
    if(item){
        undo.push(item);
        $("#neoContentContainer").html(item);
    }
    update_buttons();
}
function update_buttons(){
    if(undo.length == 0){
        $('button[data-id="undo"]').attr('disabled',true);
    } else {
        $('button[data-id="undo"]').attr('disabled',false);
    }

    if(redo.length == 0){
        $('button[data-id="redo"]').attr('disabled',true);
    } else {
        $('button[data-id="redo"]').attr('disabled',false);
    }
}

https://jsfiddle.net/s1L6vv5y/

Not perfect, but get the jist of it. (Still wondering when we can get ONE LINE LINE BREAKS!!!! DEVS AT STACKOVERFLOW!! :)

So when my page loads, I run: editor_add(); Because when they do something, it needs to undo to something!

Now every time they drop something, sort things I run editor_add(); Took me all day, now realizing how simple it was this works very well for me.

So with this one, which is good....

var history = function() {
    this.done = this.reverted = [];
    var self = this;

    this.add = function(item) {
        self.done.push(item);
    };

    this.undo = function() {
        if(done.length >= 3){
            var undo_item = self.done.pop();
            self.reverted.push(undo_item);
        }

        var item = self.done.pop(); 
        if (item) {
            self.reverted.push(item);
        }

        return item;
    };

    this.redo = function() {
        if(reverted.length >= 3){
            var revert_item = self.reverted.pop();
            self.done.push(revert_item);
        }
        var item = self.reverted.pop();
        if (item) {
            self.done.push(item);
        }

        return item;
    };
};

You do not want to clear the redos until you ran through the array.

(Guess logging in before editing helps!)



来源:https://stackoverflow.com/questions/5617447/apply-undo-redo-on-elements-that-can-dragable-drag-and-drop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!