成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖形編輯器:歷史記錄設計

開發 前端
要記錄圖形編輯器的歷史記錄,支持撤銷重做功能,需要兩個棧:撤銷(undo)棧和重做(redo)棧。

大家好,我是前端西瓜哥。今天講一下圖形編輯器如何實現歷史記錄,做到撤銷重做。

其實就是版本號的更替。每個版本保存一個狀態。

數據結構

要記錄圖形編輯器的歷史記錄,支持撤銷重做功能,需要兩個棧:撤銷(undo)棧和重做(redo)棧。

每當用戶進行一個操作(比如移動一個圖形),就會產生一個新的版本,將這個操作產生的狀態保持加入到 undo 棧頂,此外 redo 棧會清空。因為用戶可能撤銷了幾次然后產生了新的操作,無法重做它們了。

當用戶撤銷,undo 棧出棧,并放到 redo 棧,然后使用 undo 棧頂的狀態。當用戶重做時,redo 棧出棧,再放到 undo 棧上,并應用 undo 棧頂的狀態。

原理大概這樣。

瀏覽器的回退前進的表現其實就是一個很常見的例子。

數據結構還有另一種方案:雙向鏈表加兩個指針,一個指針指向當前版本狀態,另一個指針指向 redo 最后一次可執行到達的狀態。

然后是如果要支持協同的場景,你的撤回不會回到之前的版本,而是將之前的版本的狀態拿出來作為一個新的版本。

協同中你也不能撤回別人的操作,只能撤回自己的,并且要用協同算法處理和其他協同者的沖突邏輯。

要保存哪些狀態

那么我們的狀態要保存哪些狀態呢?

  1. 圖形樹數據
  2. 圖形樹需要的引用
  3. 一些設置

圖形樹是必要的,我們需要用它渲染畫布內容。此外還有游離在圖形樹之外的被用到的對象,比如圖層、被多次引用的圖形。你可以也把它們也放到圖形樹里面去。

最后是一些需要共享的設置,比如表格的行高、篩選條件等。

像是顏色主題、國際化語言設置則不需要歷史記錄,它是用戶自己選擇的個性化定制。

我們看具體的幾種實現。

全量快照

每次操作得到的新狀態,完全拷貝一份保存起來。

因為對象如果只是淺拷貝,其中的引用對象可能會被意外地修改,通常我們會選擇 序列化成字符串 保存,即JSON.stringify。撤銷重做的時候再解析出來作為當前狀態。

優點是實現簡單。巨大的優點。

缺點是當狀態很大的時候,每次生成快照都會比較耗時,且操作很多產生很多版本時,需要大量的內存空間保存這些完整狀態。

如果畫布上有一萬個獨立的實體,就意味著每進行一次操作,就要將這個一萬個實體深拷貝一份。100 次就是 100w,很恐怖。

僅推薦簡單的圖形編輯器使用,或者做 demo 用。

補丁(patch)

全量快照讓編輯器的上限很低,不是最優解。

一種更好的解法,是 打補丁(patch)。

基于上一個版本 1,打一個補丁,變成下一個版本 2。同時我們記錄一個反向的補丁,撤回的時候能通過它從版本 2 回到版本 1。

這個方案對應了設計模式的 命令模式,我們構建 Command 類,這個類有 execute、redo、undo 方法,這些方法會對傳入的舊的狀態對象打補丁,得到一個新的狀態。

比如添加矩形命令,execute 和 redo 時我們會往圖形樹的末尾加一個矩形對象,undo 就是將這個矩形從圖形樹中移除。undo 棧和 redo 棧此時記錄的就是一個個 command 對象了。

圖片

純純用樸實無華的命令模式去實現,還是有點坑的。因為要實現的命令太多了,比如添加圖形、修改圖形屬性、刪除圖形、對幾個圖形做右對齊等,這些都要自己一個個實現 redo 和 undo。復雜一點就要抓瞎,建議找一些輪子。比如 immer、y.js。

使用補丁方案還有一個好處,就是方便實現 “動作” 功能。(當然這不是一個優先級很高的功能)

比如我們想要給一個圖形先順時針旋轉 45 度,然后向右移動 10 個單位,我們希望記錄這兩個操作,給其他圖形也應用這些操作。

快照的方式就不好搞,或許我們可以對比新舊狀態找不同推斷出行為,但不好搞。因為屬性的變化可能來自不同的操作,比如移動,可以通過移動工具相對位移產生,也可能直接屬性面板改 x 值,也可能是通過對齊操作產生的。

patch 就很適合。

什么時候保存狀態

我們需要確認一個操作完成的時刻,將它加入到歷史記錄中。

我們操作圖形,會產生一些 中間狀態。比如移動一個圖形,拖拽的過程中不生產一個歷史版本,直到拖拽結束才記錄。

一種方式是:操作圖形的替身,操作結束后才更新真正的狀態。

一些編輯器,比如 Adobe Illustrator、AutoCAD,我們在操作圖形的時候,會看到一個臨時的替身,就是將被選中圖形的輪廓線或拷貝做鼠標的跟隨,鼠標釋放后才真正修改圖形屬性。

還比如顏色的修改,在拾色器中挑選顏色時不會立即修改圖形,在點擊確認才真正修改圖形顯示在畫布上。

圖片

另一種方式是:直接操作真正的狀態,在操作結束的時候,記錄這個時刻的狀態。

圖片

第一種方式的好處是,狀態沒有中間狀態,替身操作完,計算出新狀態應用到真正的狀態上就好了。

第二種方式就要額外在操作開始時,保存原始狀態的快照,因為之后我們會產生中間狀態,然后在操作結束后計算 patch。

但第二種方式用戶體驗會更好些,用戶能實時看到一個圖形的變化,判斷是不是自己需要的效果,而不是看到一個 “通往未來的幻影”。

責任編輯:姜華 來源: 前端西瓜哥
相關推薦

2024-01-22 10:01:41

Git 提交快照

2009-08-20 16:25:05

Linux系統歷史記錄linux

2011-10-09 14:57:35

2013-12-05 17:37:57

Windows 8文件歷史記錄

2021-04-27 15:38:10

GoogleChrome歷史記錄

2017-03-27 16:15:42

ChromeVivaldi瀏覽器

2022-01-25 11:33:14

數據泄露網絡攻擊

2009-07-07 15:49:04

root命令歷史記錄安全性 

2021-01-06 18:10:22

ShellLoki系統運維

2013-01-21 14:37:05

Windows 8歷史記錄

2021-12-15 23:33:33

Windows 11Windows微軟

2023-10-19 10:12:34

圖形編輯器開發縮放圖形

2016-01-27 11:24:20

Windows 10紅石鏡像

2016-01-26 15:27:16

Windows 10歷史記錄備份

2023-08-01 09:30:12

SQL Server數據庫

2021-01-20 09:29:09

QQ瀏覽器App

2022-04-29 16:47:57

AI騰訊

2023-06-02 10:41:50

2019-10-14 16:16:49

BashLinux命令

2020-06-01 18:20:41

Git
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 美女福利视频网站 | 亚洲乱码一区二区三区在线观看 | 北条麻妃一区二区三区在线观看 | 国内精品久久精品 | 99久久婷婷国产综合精品电影 | 国产精品一卡二卡三卡 | 在线观看视频福利 | 欧美久久天堂 | 午夜视频免费在线观看 | 91精品国产色综合久久 | 精品久久久久一区 | 电影午夜精品一区二区三区 | 成人免费av| 久久草视频 | 在线观看成人免费视频 | 蜜月aⅴ国产精品 | 国产美女久久久 | 超碰人人在线 | 91高清视频在线 | 中文字幕亚洲区 | 久久亚洲国产精品日日av夜夜 | 蜜桃av鲁一鲁一鲁一鲁 | 久久国产一区二区三区 | 欧美在线视频一区二区 | 亚洲一区二区在线免费观看 | 伊人春色在线观看 | 成人精品在线观看 | 羞羞免费网站 | 亚洲精品久久久久久一区二区 | 久久九 | 中文一区 | 午夜电影福利 | 女人毛片a毛片久久人人 | 毛片a级 | 精品熟人一区二区三区四区 | 青青草原综合久久大伊人精品 | 欧美综合一区二区 | 成人免费观看男女羞羞视频 | 欧美涩| 欧洲色综合 | 97精品超碰一区二区三区 |