【发布时间】:2011-04-11 06:16:31
【问题描述】:
我想在 svgElements 上实现可以用 javascript 拖动的功能,我该怎么做...
我已经用鼠标向上实现了这个
当鼠标向上时,我保存 x 和 y 位置、对象 id、对象类型(圆、矩形等)
谁能告诉...这是实施的好方法吗?
【问题讨论】:
标签: javascript svg undo-redo
我想在 svgElements 上实现可以用 javascript 拖动的功能,我该怎么做...
我已经用鼠标向上实现了这个
当鼠标向上时,我保存 x 和 y 位置、对象 id、对象类型(圆、矩形等)
谁能告诉...这是实施的好方法吗?
【问题讨论】:
标签: javascript svg undo-redo
如果您要问如何实现一般的撤消/重做功能,这很简单:您有一组动作和一个计数器。当动作发生时你将新元素推入数组,当人们点击撤消时后退。
非常基本的实现:
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
}
};
请注意,应该有基本的错误检查以查看计数器不会超出范围,并且您可能希望在撤消的情况下将“撤消”信息传递给 doSomethingWith,但所有这些都是特定于应用程序的。
【讨论】:
cwolves 描述了一个很好的撤销/重做功能结构。
您是对的,在鼠标按下期间,您需要存储历史记录,但您还需要存储在鼠标按下期间被操作对象的原始位置,这样您就可以撤消移动时拥有它。
如果您最终更进一步并允许缩放,那么您将需要存储完整的原始变换,例如“translate(10,10) scale(1.2,1.2) rotate(90)”,用于历史记录,但也可以让您有一个基线来应用拖动缩放操作。
【讨论】:
我找到了一个更好的结构,没有计数器、索引移位或限制处理问题。 只需 2 叠用于平衡的“完成”和“恢复”操作。
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;
};
};
【讨论】:
以上代码存在一些问题。 我尝试使用它们,发现在它开始下降阵列之前我必须先点击两次撤消。
所以说我已经完成[0] 完成[1] 完成[2]。 done[2] 刚刚保存到数组中。如果我点击撤消,它会返回。你不想要那个。它正在取代已经存在的东西。但是再次点击撤消,然后你会得到你以前的代码。
我的,因为我有一个具有不同编辑模式的拖放编辑器。拖放元素。编辑元素 HTML/图片。对元素进行排序。
$("#neoContentContainer") 包含所有编辑器 html。 而且您可以在点击、鼠标按下等时调用 editor_add... 看到它是一个您可以轻松调用的函数。
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/
不完美,但要了解它的要点。 (仍然想知道我们什么时候可以得到 ONE LINE LINE BREAKS!!!! DEVS AT STACKOVERFLOW!! :)
所以当我的页面加载时,我运行: editor_add(); 因为当他们做某事时,它需要撤消某事!
现在每次他们丢东西时,我运行 editor_add();花了我一整天,现在意识到这对我来说非常简单。
所以有了这个,很好....
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;
};
};
在遍历数组之前,您不想清除重做。
(在编辑之前猜测登录有帮助!)
【讨论】: