我做的Stylii修改一個隱藏的鎖定圖層這個問題是不是標題所暗示什麼更具體的,仿效Paper.js
,具有紙JS應用程序撤消功能來實現。
撤消功能的工作原理是這樣的:
每次的改變對那幅畫,我們把它的一個快照, 通過導出繪圖到JSON的內容。點擊UNDO,只需 清除畫布並重新導入以前的JSON快照。
要有人真的感興趣的話,這裏是代碼實現什麼上述I:
function Undo(maxUndos) {
this.states = [];
this.head = -1;
this.maxUndos = maxUndos || 10;
this.updateUI();
}
Undo.prototype.snapshot = function(name) {
// console.log("snapshot() layers: "+paper.project.layers);
// Update previous state's selection to the selection as of now
// so that undo feels more natural after undo. Omitting this
// makes the undo feel like it lost your selection.
if (this.head >= 0 && this.head < this.states.length)
this.states[this.head].selection = this.snapshotSelection();
// HACK: Store original ID into the data of an item.
this.captureIDs();
var state = {
name: name,
stamp: Date.now(),
json: this.snapshotProject(),
selection: this.snapshotSelection()
};
// Discard states after the current one.
if (this.head < this.states.length-1)
this.states = this.states.slice(0, this.head+1);
this.states.push(state);
// Remove the oldest state if we have too many states.
if (this.states.length > this.maxUndos)
this.states.shift();
this.head = this.states.length-1;
this.updateUI();
}
Undo.prototype.restoreIDs = function() {
// Restore IDs from the 'data'.
var maxId = 0;
function visitItem(item) {
if (item.data.id) {
item._id = item.data.id;
if (item.id > maxId)
maxId = item.id;
}
if (item.children) {
for (var j = item.children.length-1; j >= 0; j--)
visitItem(item.children[j]);
}
}
for (var i = 0, l = paper.project.layers.length; i < l; i++) {
var layer = paper.project.layers[i];
visitItem(layer);
}
if (maxId > paper.Item._id)
Item._id = maxId;
}
Undo.prototype.captureIDs = function() {
// Store IDs of the items into 'data' so that they get serialized.
function visitItem(item) {
item.data.id = item.id;
if (item.children) {
for (var j = item.children.length-1; j >= 0; j--)
visitItem(item.children[j]);
}
}
for (var i = 0, l = paper.project.layers.length; i < l; i++) {
var layer = paper.project.layers[i];
visitItem(layer);
}
}
Undo.prototype.snapshotProject = function() {
var json = paper.project.exportJSON({ asString: false });
return json;
}
Undo.prototype.snapshotSelection = function() {
var selection = [];
var selected = paper.project.selectedItems;
for (var i = 0; i < selected.length; i++) {
var item = selected[i];
if (item.guide) continue;
var state = {id: item.id, segs: []};
if (item instanceof paper.Path) {
var segs = [];
for (var j = 0; j < item.segments.length; j++) {
if (item.segments[j].selected)
segs.push(item.segments[j].index);
}
if (segs.length > 0) {
state.segs = segs;
}
}
selection.push(state);
}
return selection;
}
Undo.prototype.restoreSelection = function(sel) {
paper.project.deselectAll();
// HACK: some logic in Paper.js prevents deselectAll in some cases,
// enforce deselect.
paper.project._selectedItems = {};
for (var i = 0; i < sel.length; i++) {
var state = sel[i];
var item = findItemById(state.id);
if (item == null) {
console.log("restoreSelection: could not find "+state.id);
continue;
}
item.selected = true;
for (var j = 0; j < state.segs.length; j++) {
var idx = state.segs[j];
if (idx >= 0 && idx < item.segments.length)
item.segments[idx].selected = true;
}
}
}
Undo.prototype.restore = function(state) {
// Empty the project and deserialize the project from JSON.
paper.project.clear();
paper.project.importJSON(state.json);
// HACK: paper does not retain IDs, we capture them on snapshot,
// restore them here.
this.restoreIDs();
// Selection is serialized separately, restore now (requires correct IDs).
this.restoreSelection(state.selection);
// Update UI
updateSelectionState();
paper.project.view.update();
}
Undo.prototype.undo = function() {
if (this.head > 0) {
this.head--;
this.restore(this.states[this.head]);
}
this.updateUI();
}
Undo.prototype.redo = function() {
if (this.head < this.states.length-1) {
this.head++;
this.restore(this.states[this.head]);
}
this.updateUI();
}
Undo.prototype.canUndo = function() {
return this.head > 0;
}
Undo.prototype.canRedo = function() {
return this.head < this.states.length-1;
}
Undo.prototype.updateUI = function() {
if (this.canUndo())
$("#undo").removeClass("disabled");
else
$("#undo").addClass("disabled");
if (this.canRedo())
$("#redo").removeClass("disabled");
else
$("#redo").addClass("disabled");
}
var undo = null;
現在,這造成在許多層面上的問題:
這是不可能有元素,例如幫助線,網格等在 圖紙上,因爲它們被撤銷JSON的。在導出/重新導入過程中,它也很難繞過它們 - 這樣做的邏輯確實可以完成。
電網「」系統「」我設計的基本重繪每個變焦 水平網格,使其更快,而不是一個巨大的靜態之一 - 邏輯來實現,這是一個有點複雜,因此implimenting 邏輯那也會在Undo JSON快照期間跳過網格,然後重新繪製它 - 這將使其不僅成爲惡夢,而且還將維持和擴展 。
這是一個JSFiddle,顯示瞭如何滾動縮放到鼠標和動態網格的概念一起工作。
反正夢幻的情況是這樣的:
會有2層:
主層 - 是繪圖發生,撤消快照僅 靶這圖層和撤消恢復僅適用於此圖層。
頂層 - 是靜態的,不可撤消的,不可輸出的,不可選元素被放置。這個圖層也應該是 對鼠標事件透明,因爲我們希望它位於頂部 (網格應該出現在所有元素的頂部)。
PS:當然滾動換變焦一個層上的應適用於兩個層由於網格被認爲是可縮放的太。
我知道這種情況不能輕易實現,因爲Paper.js不提供這種開箱即用的東西,但也許有一些解決方法的想法?
任何想法,將有極大的幫助,相信我,我如鯁在一家糖果店糖尿病。
PS:我已經嘗試在堆疊在paper.js-canvas頂部的單獨畫布上使用單純的Canvas繪圖命令繪製網格。我用指針事件穿過它的點擊次數和目標「」主「」在它下面的畫布。這可以工作,但網格不能交互(鎖定到網格的人?),這整個事情在未來的可擴展性方面氣味腥。