Undo1.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <div>
  3. <el-button @click="addCircle">Circle</el-button>
  4. <el-button @click="addRect">Rect</el-button>
  5. <el-button @click="deleteItem">Delete</el-button>
  6. <el-button @click="undo">Undo</el-button>
  7. <el-button @click="redo">Redo</el-button>
  8. <canvas id="undoFrame" width="800" height="400" />
  9. </div>
  10. </template>
  11. <script lang="ts">
  12. import { SMouseEvent, SUndoStack } from "@saga-web/base";
  13. import { SColor, SPainter, SRect } from "@saga-web/draw";
  14. import { SGraphyItem, SGraphyScene, SGraphyView } from "@saga-web/graphy";
  15. import {SGraphyCommand} from "@saga-web/graphy/lib";
  16. import {SUndoCommand} from "@saga-web/base/lib";
  17. import {SPoint} from "@saga-web/draw/lib";
  18. class RectItem extends SGraphyItem {
  19. width = 100;
  20. height = 100;
  21. constructor(parent: SGraphyItem | null) {
  22. super(parent);
  23. this.moveable = true;
  24. this.selectable = true;
  25. this.selected = true;
  26. }
  27. boundingRect(): SRect {
  28. return new SRect(0, 0, this.width, this.height);
  29. }
  30. onDraw(canvas: SPainter): void {
  31. canvas.pen.color = SColor.Blue;
  32. canvas.pen.lineWidth = 5;
  33. canvas.brush.color = this.selected ? SColor.Red : SColor.Green;
  34. canvas.drawRect(0, 0, this.width, this.height)
  35. }
  36. }
  37. class CircleItem extends SGraphyItem {
  38. r = 50;
  39. constructor(parent: SGraphyItem | null) {
  40. super(parent);
  41. this.moveable = true;
  42. this.selectable = true;
  43. }
  44. boundingRect(): SRect {
  45. return new SRect(0, 0, this.r * 2, this.r * 2);
  46. }
  47. onDraw(canvas: SPainter): void {
  48. canvas.pen.color = SColor.Blue;
  49. canvas.pen.lineWidth = 5;
  50. canvas.brush.color = this.selected ? SColor.Red : SColor.Green;
  51. canvas.drawCircle(this.r, this.r, this.r);
  52. }
  53. }
  54. class SScene extends SGraphyScene {
  55. undoStack = new SUndoStack();
  56. /** 定义命令 */
  57. cmd = 0;
  58. constructor() {
  59. super();
  60. }
  61. onMouseUp(event: SMouseEvent): void {
  62. switch(this.cmd) {
  63. case 1:
  64. this.addCircle(event.x, event.y);
  65. break;
  66. case 2:
  67. this.addRect(event.x, event.y);
  68. break;
  69. default:
  70. super.onMouseUp(event);
  71. }
  72. this.cmd = 0;
  73. }
  74. private addCircle(x: number, y: number): void {
  75. let item = new CircleItem();
  76. item.moveTo(x - 50, y - 50);
  77. this.addItem(item);
  78. this.undoStack.push(new SGraphyAddCommand(this, item));
  79. item.connect("onMove", this, this.onItemMove.bind(this));
  80. }
  81. private addRect(x: number, y: number): void {
  82. let item = new RectItem();
  83. item.moveTo(x - 50, y - 50);
  84. this.addItem(item);
  85. this.undoStack.push(new SGraphyAddCommand(this, item));
  86. item.connect("onMove", this, this.onItemMove.bind(this));
  87. }
  88. onItemMove(item: SGraphyItem, ...arg: any): void {
  89. this.undoStack.push(new SGraphyMoveCommand(this, item, arg[0][0] as SPoint, arg[0][1] as SPoint));
  90. }
  91. }
  92. class TestView extends SGraphyView {
  93. constructor() {
  94. super("undoFrame");
  95. }
  96. }
  97. class SGraphyAddCommand extends SGraphyCommand {
  98. item: SGraphyItem;
  99. parent: SGraphyItem | null;
  100. constructor(scene: SGraphyScene, item: SGraphyItem) {
  101. super(scene);
  102. this.item = item;
  103. this.parent = item.parent;
  104. }
  105. mergeWith(command: SUndoCommand): boolean {
  106. return false;
  107. }
  108. redo(): void {
  109. this.item.parent = this.parent;
  110. this.parent.update();
  111. }
  112. undo(): void {
  113. this.item.parent = null;
  114. this.parent.update();
  115. }
  116. }
  117. class SGraphyDeleteCommand extends SGraphyCommand {
  118. mergeWith(command: SUndoCommand): boolean {
  119. return false;
  120. }
  121. redo(): void {
  122. }
  123. undo(): void {
  124. }
  125. }
  126. class SGraphyMoveCommand extends SGraphyCommand {
  127. item: SGraphyItem;
  128. old: SPoint;
  129. pos: SPoint;
  130. constructor(scene: SGraphyScene, item: SGraphyItem, old: SPoint, pos: SPoint) {
  131. super(scene);
  132. this.item = item;
  133. this.old = old;
  134. this.pos = pos;
  135. }
  136. mergeWith(command: SUndoCommand): boolean {
  137. if (command instanceof SGraphyMoveCommand && command.item == this.item) {
  138. command.pos = this.pos;
  139. return true;
  140. }
  141. return false;
  142. }
  143. redo(): void {
  144. this.item.pos = new SPoint(this.pos.x, this.pos.y);
  145. this.item.update();
  146. }
  147. undo(): void {
  148. this.item.pos = new SPoint(this.old.x, this.old.y);
  149. this.item.update();
  150. }
  151. }
  152. export default {
  153. data() {
  154. return {
  155. scene: new SScene(),
  156. }
  157. },
  158. mounted(): void {
  159. let view = new TestView();
  160. view.scene = this.scene;//new SScene(); //this.data.scene;
  161. },
  162. methods: {
  163. addCircle() {
  164. this.scene.cmd = 1;
  165. },
  166. addRect() {
  167. this.scene.cmd = 2;
  168. },
  169. deleteItem() {
  170. },
  171. undo() {
  172. console.log("undo");
  173. this.scene.undoStack.undo();
  174. },
  175. redo() {
  176. this.scene.undoStack.redo();
  177. }
  178. }
  179. }
  180. </script>
  181. <style scoped>
  182. </style>