# project-1 **Repository Path**: lijb55/project-1 ## Basic Information - **Project Name**: project-1 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 9 - **Created**: 2022-06-16 - **Last Updated**: 2022-06-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 在线 SVG 编辑器 ##### 主要实现内容,在控制面板中添加了撤销,返回,复制,粘贴选项。 - undo&redo - 撤销和返回功能,选中左边面板的undo键,随后点击任意地方,画板将返回上一次操作执行前的状态,选中redo键,取消撤销。当undo状态撤销操作后,接上后续操作,则无法再redo: image-20220616192044905 微信截图_20220616192520 微信截图_20220616192616 - 实现方式: (1)维护一个全局变量列表保存每次更新前的状态,在ResizeController的drag函数,append和remove函数中,每一次变换前(增删改)保存操作对象和操作方式。 ```python def drag(self, x1, y1, x2, y2, drag_event): if drag_event is not None: c, action = drag_event c.drag(action, x1, y1, x2, y2) return drag_event for c in self.controller_panel.svg.children[::-1]: # 在变换前存储状态,用于撤销操作 s = {c.elt:c.getAttribute()} move_stack.push('state') state_stack.push(s) action = c.action(x1,y1) if action!='auto': c.drag(action, x1, y1, x2, y2) return [c, action] ``` (2)对于撤销返回,因为之前记录的是最后一次操作之前的内容,所以最新的内容是没有记录,需要额外一个变量记录当前状态并加入列表中。通过一个current_state指针找到需要变到哪个状态。 (3)当撤销后,接着create或resize或remove操作时,此时redo将不可用,则将列表中当前状态后的所有状态删除。 ```python while self.current_state < self.len: self.items.pop() self.len = self.len-1 ``` - copy&paste - 复制粘贴功能,选中控制面板的复制,点击想要复制的对象,则将记录该对象的类和属性;选中控制面板的粘贴,点击任意位置,在原对象附近生成新的复制对象: ![image-20220616192141011](img/image-20220616192141011.png) - 实现方式: (1)保存一个全局变量记录鼠标选中的对象,记录其类型和参数,再粘贴时将内容的类和属性保存下来,然后新建类和加入svg子图中。 ```python class CopyController(Controller): def __init__(self): super(CopyController,self).__init__() shape = _make_svg('path', {'d':"M6 6V2c0-1.1.9-2 2-2h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-4v4a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8c0-1.1.9-2 2-2h4zm2 0h4a2 2 0 0 1 2 2v4h4V2H8v4zM2 8v10h10V8H2z", 'fill':'#486e93', 'stroke':'black', 'stroke-width':1, 'transform':"translate(6,6)"}) self.svg.appendChild(shape) def click(self, x, y): for c in self.controller_panel.svg.children[::-1]: action = c.action(x,y) if action!='auto': global copy copy = {c.elt:c} break def move(self, x, y): for c in self.controller_panel.svg.children[::-1]: action = c.action(x,y) if action!='auto': self.controller_panel.svg.div.style.cursor = "pointer" break else: self.controller_panel.svg.div.style.cursor = 'auto' class PasteController(Controller): def __init__(self): super(PasteController,self).__init__() shape = _make_svg('path', {'d':"M10.5 20H2a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h1V3l2.03-.4a3 3 0 0 1 5.94 0L13 3v1h1a2 2 0 0 1 2 2v1h-2V6h-1v1H3V6H2v12h5v2h3.5zM8 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm2 4h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2v-8c0-1.1.9-2 2-2zm0 2v8h8v-8h-8z", 'fill':'#486e93', 'stroke':'black', 'stroke-width':1, 'transform':"translate(6,6)"}) self.svg.appendChild(shape) def click(self, x, y): for item in copy.items(): print("create") print(item[1]) if item[1].getName() == 'Rect': p = [] for i in item[1].getAttribute().items(): p.append(i[1]) x = p[0] y = p[1] width = p[2] height = p[3] rect = Rect(x-50, y-50, width, height) self.controller_panel.svg.append(rect) elif item[1].getName() == 'Eclipse': p = [] for i in item[1].getAttribute().items(): p.append(i[1]) x = p[0] y = p[1] width = p[2] height = p[3] eclipse = Eclipse(x-50, y-50, width, height) self.controller_panel.svg.append(eclipse) else: print("wrong class") ```