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 m
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!)
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.
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[++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
}
};
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.
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;
};
};